You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This commit was created on GitHub.com and signed with GitHub’s verified signature.
Fixed
Hub de e-mails não oferecia um token que o próprio padrão usa (#1143): a lista de ajuda por e-mail é texto escrito à mão ao lado de um template mantido em outro lugar, então ela deriva em silêncio — nas duas direções. Guarda nova compara catálogo, allowlist e arquivos: um token usado no corpo padrão e ausente da lista falha o CI.
E-mail de aprovação de agendamento não trazia o link de cancelamento (#1143): num calendário que exige aprovação, o e-mail da reserva só diz "aguardando aprovação, você receberá a confirmação" — a confirmação é o e-mail de aprovação, e ele era o único dos cinco e-mails de agendamento sem o link. Quem tinha o agendamento de fato confirmado era justamente quem não conseguia cancelar pela caixa de entrada. A cobertura existente provava o token resolvendo dentro de um override do hub, o que não diz nada sobre o corpo que uma instalação sem override recebe.
Campo numérico do admin salvava valor inválido pelo autosave (#1114): o widget salva a cada tecla e nunca consultava a validade do campo, então min, max e step eram decorativos ali — vazio, negativo e decimal passavam. Os dois caminhos de autosave passam a recusar o que o navegador considera inválido; toggles não são afetados.
Limpar um limite na aba Rate Limit gravava zero e bloqueava o eixo inteiro (#1114): os checadores leem contagem >= 0 como "limite já atingido", então um ip_max_per_hour apagado barrava toda submissão de todo endereço. Campo vazio ou ausente passa a manter o valor gravado, com piso igual ao min que o próprio campo declara.
Campo obrigatório no perfil de usuário não era exigido em ponta nenhuma (#1120): is_required só desenhava o asterisco — nenhum input emitia o atributo e o salvamento não conferia a flag, então um campo marcado obrigatório gravava vazio em silêncio. Agora o navegador exige e o servidor preserva o valor gravado quando o campo chega vazio, avisando quais preservou.
Limpar o campo de lembrete de uma campanha de rerrematrícula gravava zero (#1117): absint( '' ) é 0, e a varredura lê DATEDIFF(end_date, CURDATE()) <= reminder_days — o lembrete passava a sair só no último dia da campanha, tarde demais para servir, sem nada na tela dizendo que o valor mudou.
Limpar um campo numérico no admin gravava o piso daquela chave, em silêncio (#1111): (int) '' é 0, então esvaziar o campo escrevia o menor valor aceito — e o autosave salva a cada tecla, então bastava apagar para retomar a digitação. O endpoint agora recusa valor vazio e mantém o gravado; 0 digitado continua valendo.
O e-mail de acesso concedido nunca foi enviado por nenhuma instalação (#1123): notify_capability_grant guardava o envio e não era escrita em lugar nenhum — nem campo, nem allowlist, nem padrão declarado — então a guarda lia false para sempre, enquanto o hub de e-mails oferecia o texto para edição. Ganhou interruptor na aba SMTP, desligado por padrão para preservar o comportamento de hoje.
Linha de horário de trabalho pela metade era gravada em silêncio (#1128): a guarda do servidor era isset( $entry['entry1'] ), e isset( '' ) é verdadeiro — então uma linha com horário vazio passava. O formulário público de recadastramento era ainda mais permissivo: conferia só o dia. Agora um só sanitizador decide pelas duas telas.
Reativar uma campanha de recadastramento não avisava ninguém (#1125): ao expirar, as submissões pendentes viram expired; a reativação não as reabria — e a semeadura pula quem já tem linha — então o usuário ficava num estado que nem deixava enviar nem desenhava aviso. O convite por e-mail também não saía, porque busca só pending. Reativar agora reabre as expired, sem tocar em approved/submitted.
Quem entra na audiência depois da ativação não via a campanha (#1125): a semeadura é evento único na transição para ativa, então esse usuário nunca ganhava linha e caía no mesmo vão mudo. Agora "sem submissão" é um estado que pode enviar — o que também cobre a submissão excluída pelo administrador, devolvendo o usuário ao início.
Modo escuro: as 28 folhas passam a pintar pela paleta (#1126): metade delas não usava token nenhum — calendário, encurtador, recrutamento, recadastramento, submissões, painel de certificados, público-alvo, modelo de e-mail e as demais pintavam com hex fixo, então badges, modais, tabelas e o balão de toast ficavam claros dentro da tela escura. A catraca bloqueia em zero; o que segue literal é decisão com o motivo escrito ao lado.
A paleta precisa estar na página, e ela não estava — de quatro formas (#1126): uma custom property não declarada invalida a declaração inteira, não cai para o literal anterior. Dezesseis enfileiramentos liam var(--ffc-*) sem declarar ffc-common; o dashboard e a lista de editais redeclaravam --ffc-* localmente, o que sombreia a paleta para tudo ali dentro; duas regras liam token que nunca existiu, escondidas atrás do valor de reserva; e a página pública de cancelamento monta o próprio documento, então nunca passou pelo enfileiramento — ficou sem fundo, sem cor de texto e com o botão despintado, nos dois temas.
O interruptor não chegava a quatro telas públicas (#1126): calendário, público-alvo (dois caminhos) e editais enfileiravam a paleta mas não o script que põe .ffc-dark-mode no <html>. Sem ele todo var(--ffc-*) resolve pelo bloco claro, por mais tokenizada que a folha esteja. A paleta sozinha não é o tema.
Texto que não declara cor herdava quase-preto, e controle de formulário nem isso (#1126): quem não declara color herda de fora do plugin — do body do wp-admin ou do tema — e cai em 1,28:1 sobre fundo escuro; era a legenda do calendário e o rótulo "Modelo:". Um <button>, <input>, <select> ou <textarea>não herda color e nem a regra de base o alcança: eram 18, incluindo todo campo do formulário público de recadastramento e da edição de perfil. As tarjas do admin precisaram de terceira resposta — nomear os nós de texto, porque qualquer declaração direta vence um valor herdado.
opacity e .alternate: dois defeitos que nenhum token corrigiria (#1126): a linha passada/cancelada da agenda levava opacity, que desbota texto e fundo juntos e derruba qualquer contraste que os tokens garantiram — 3,11:1 medido. E .alternate é a terceira forma de zebrar linha do WordPress, a que o plugin escreve à mão sete vezes só na aba de Cache.
Cor inline vencia a folha tokenizada (#1126): o aviso de e-mails desligados carregava a paleta inteira num style="" do PHP, em cinco telas; badges e faixas de edital fixavam #333 sobre uma cor que o administrador escolhe. Para o segundo caso nenhum token serve — o texto passa a ser calculado por luminância WCAG, com 4,58:1 garantido sobre qualquer cor do cubo RGB.
Três rótulos de botão reprovavam o contraste (#1126): sucesso (3,35:1) e aviso (3,04:1) sobre branco, e .ffc-text-warning usando cor de sinal como texto. O verde escureceu para #00801e; nasceram os pares on-success e on-warning — o primeiro inverte entre os temas, o segundo não, porque o aviso é tom médio-claro nos dois.
Trocar o modo escuro só valia no carregamento seguinte (#1126): o seletor salva sozinho, mas nada repintava a página — nas duas direções, o que se lê como um salvamento que falhou. O autosave passa a anunciar o que gravou e o script do tema aplica na hora, inclusive parando de seguir o sistema operacional ao sair do "automático".
Dez pares de cor da paleta reprovavam o contraste mínimo (#1132): o pior era o rótulo do botão primário no tema escuro — branco sobre a primária clara, 2,52:1, desde que o tema escuro existe. O Material 3 inverte esse par no escuro (a primária clareia, o texto sobre ela escurece) e o plugin só tinha feito metade. Corrigidos também os contornos de campo e card nos dois temas e o anel de foco, que compunha 1,78:1 no claro.
Placeholder e indicador de aviso ficaram mais escuros no tema claro (#1132): #8c8f94 e #dba617 vêm da paleta do próprio WordPress e reprovavam 3,24:1 e 2,22:1. A correção afasta um pouco o plugin do visual do wp-admin — foi decisão deliberada, em favor da legibilidade.
Cinco dos oito mutadores de audiência não invalidavam o cache de audiências do usuário (#1127): a chave morava num grupo literal próprio, fora do par Reader/Writer, então cada mutador tinha de lembrar sozinho — e bulk_add_members(), o caminho do admin, não lembrava. Decidia errado a campanha de recadastramento no painel e os campos personalizados no perfil. A chave passa a morar no grupo do par, com um só ponto de invalidação e TTL, que antes não havia.
Sair de uma audiência não limpava o cache de quem saiu (#1127): set_members() invalidava só a lista que entrava, então quem era removido seguia vendo a audiência. cascade_self_join() não invalidava nada — nem por id, nem a versão de consulta — e altera allow_self_join, que a lista devolve.
Changed
Cancelar um agendamento pelo painel passa a abrir um diálogo, não um confirm() (#1140): o confirm() não dizia qual agendamento seria cancelado e não tinha campo de motivo — então um cancelamento pelo painel gravava motivo vazio enquanto o mesmo pelo link do e-mail gravava o que a pessoa escreveu. O endpoint já aceitava e sanitizava reason; a lacuna era só do cliente. O diálogo mostra serviço e data/hora, e reaproveita as mesmas strings da página pública.
Modal vira componente compartilhado na paleta (#1140): havia duas cópias — uma no público-alvo, outra no admin de recadastramento — e o painel seria a terceira. A do público-alvo foi para ffc-common.css, que toda folha que já a usava declara como dependência. A do admin ficou onde está: seletores sem escopo, outra tela.
Entradas numéricas do admin fora das abas de configuração agora exigem valor (#1117): 19 campos ganharam required — auto-agendamento, quiz, recrutamento, rerrematrícula e modelo de e-mail. Oito ficaram de fora, cada um com o motivo travado em teste: em cinco vazio significa "herdar o global" ou "sem limite", um não é campo de formulário, e em dois a obrigatoriedade pertence à definição do campo.
required passa a acompanhar os blocos que o JS esconde (#1117, #1120): campo obrigatório escondido trava o envio apontando para um controle que ninguém vê. Fecha junto dois casos já vivos — as linhas de horário de trabalho do editor de calendário, e os dois campos de hora do perfil de usuário, obrigatórios dentro de seções recolhíveis.
Os dois caminhos de autosave do admin viraram um só widget (#1116): o data-ffc-autosave-form-key tinha implementação própria em ffc-admin.js — mesmo trabalho, outro evento, outro badge — e a guarda de validade do #1114 precisou ser escrita duas vezes para alcançar os dois. Agora um widget lê os dois atributos; os endpoints seguem separados, com capacidade e nonce próprios.
Badge de autosave dos metaboxes passa a seguir o modo escuro (#1116): usava hex fixo em vez dos tokens --ffc-*. De quebra, distingue queda de conexão de recusa do servidor, que a implementação antiga achatava num "falha ao salvar" genérico, e os textos das abas de configuração deixam de ser literais em inglês no JS.
Entradas numéricas das abas de configuração agora são obrigatórias (#1114): 38 campos ganharam required, e o smtp_port — o único sem limite algum — ganhou faixa. Os caps de endpoint de leitura passam a dizer no próprio card que ali 0 remove o limite, ao contrário dos demais.
Piso da janela de emissão de captcha baixado de 60s para 1s (#1111): abaixo de um minuto o limite vira decorativo — o campo passa a dizer isso como recomendação, em vez de o código recusar, alinhando com os demais limites da aba.
Horário de trabalho: a regra da linha agora é exigida, e antes do envio (#1128): entrada do primeiro turno e saída do último são obrigatórias, o intervalo é opcional — regra que existia só como um required no markup e que ninguém tinha escrito. Uma linha pela metade bloqueia o envio nomeando o que falta e abrindo a seção recolhida, em vez de o servidor decidir sozinho o que descartar; nada do que foi digitado se perde. ⚠ Linha sem horário nenhum deixa de ser gravada: um dia sem linha já significa "não trabalho neste dia".
Nenhum status de recadastramento produz mais tela em branco (#1125): o painel tratava approved e submitted e caía num continue mudo para todo o resto. Ganhou ramo final mostrando o status legível — os dois casos que caíam ali estão corrigidos na origem, e o ramo existe para o próximo status não repetir a história.
Modo escuro passa a repintar o que o WordPress desenha (#1126): o modo escuro era só a troca de tokens, e nada aplicava esses tokens ao chrome do core — então rótulos de form-table ficavam escuros sobre fundo escuro e os campos continuavam brancos dentro do card escuro. Rótulos, campos, cards, metaboxes, tabelas de listagem, abas, botões secundários e avisos passam a seguir a paleta. Falta ainda a metade das folhas de admin que não usam token nenhum.
Removed
⚠ O argumento $token de check_verification() (#1048): anunciado obsoleto na 6.22.0, removido agora conforme o prazo publicado. RateLimiter::check_verification() e RateLimitChecker::check_verification() passam a receber só o IP. Nenhum chamador passava o segundo argumento, e quem passar não quebra — o PHP ignora argumento excedente em função de usuário.
Sete acessores do SettingsReader que liam a opção errada (#1123): admin_bar_allowed(), wp_admin_blocked() e admins_bypassed() liam chaves de ffc_user_access_settings; ip_cache_enabled(), ip_api_enabled(), ip_cache_ttl() e gps_cache_ttl() liam chaves de ffc_geolocation_settings, duplicando acessores corretos que já existiam. Nada os chamava, e nada escrevia aquelas chaves em ffc_settings — devolviam o padrão embutido para sempre.
Added
Emissão de desafios ALTCHA agora é configurável (#1111): teto e janela no bloco de IP da aba Rate Limit, padrões 60 e 600s — os valores que já vigoravam — e teto 0 = sem limite. Era o único limite do sistema sem controle na interface: atrás de NAT institucional ele barrava o formulário para todos depois do 60º desafio, com 429 e nenhum erro visível.
Guarda de caminho de escrita sobre ffc_settings (#1123, #993): toda chave lida da opção precisa poder ser gravada nela — por campo, por allowlist de autosave ou por padrão declarado. Bloqueia em zero, sem baseline, e pega as duas formas que motivaram a issue: o acessor de chave alheia e a funcionalidade dormente. Junto vai uma catraca das 32 chaves lidas sem declaração, que só encolhe.
O guarda de modo escuro passa a medir contraste (#1132): antes só procurava cor literal — via presença, não legibilidade. Agora calcula a razão WCAG de cada par que o CSS realmente pinta, nos dois temas, e bloqueia em zero. Teria acusado o botão primário do tema escuro no dia em que ele foi escrito.
Catraca de cor literal por folha de estilo (#1126): as sete folhas convertidas bloqueiam em zero; as demais carregam o número medido como orçamento que só encolhe. Junto vai a metade que faltava — toda folha que lê var(--ffc-*) precisa declarar ffc-common como dependência, que é o que achou os dezesseis enfileiramentos sem paleta.