SRP Blog Plugin
v2.0.1
01Mapa Estrutural do Plugin
plugins_loaded para upgrade automático está registrado antes dos require_once — isso é seguro pois a ação dispara depois da execução completa do arquivo, mas merece atenção.int|false nos retornos de insert_post() e insert_category(), que exige PHP 8.0+. Compatibilidade com PHP 7.4 quebrada.wp_ajax_ e wp_ajax_nopriv_). Instancia a própria classe ao final do arquivo. Problemas críticos: (1) handle_save_cat() chama wp_send_json_error() sem return após verificar nome vazio — execução continua indevidamente. (2) handle_login() chama wp_send_json_success() dentro do foreach sem return — se o WP não encerrar a execução (em testes unitários, por ex.) pode gerar comportamento duplo. (3) handle_save_post(): falta return no bloco de falha do insert.[srp_blog_manager] e [srp_blog]. Enfileira assets CSS/JS apenas nas páginas que contêm os shortcodes. Lógica correta e bem estruturada.wp_editor() para o TinyMCE. Problema: o elemento id="srpAdminToasts" está duplicado — aparece tanto em srp_blog_admin_page_novo() quanto em srp_blog_admin_page_cats(). IDs duplicados no mesmo DOM são inválidos em HTML e causam falha no JS que busca por esse ID.$post = SRP_Blog_DB::get_post_by_slug(...)), mas todo o restante do template usa $srp_post (inexistente). Isso gera erros fatais PHP “Attempt to read property on null/non-object” em todas as páginas de post individual. O plugin não funciona neste estado.[srp_blog_manager]). Renderiza: tela de login, painel principal com abas (Posts, Criar Post, Categorias), editor rich text via contenteditable, e modais. Bem estruturado, sem erros de sintaxe.[srp_blog]). Exibe grid de cards de posts com filtros por categoria. Depende das variáveis $posts e $cats injetadas pelo shortcode — correto.srpBlogAdmin localizado via wp_localize_script(). Gerencia tabela, modais, TinyMCE, upload de imagem e HTML. Lógica correta.srpBlogData localizado via wp_localize_script(). Editor rich text via document.execCommand (API depreciada). Sem erros de sintaxe; funcional mas com dependência de API obsoleta.02Shortcodes & Credenciais de Acesso
srp-blog.php). Qualquer pessoa com acesso ao servidor ou ao repositório pode vê-las. Recomenda-se migrá-las para a tabela wp_options com hash (wp_hash_password).
Shortcodes disponíveis
[srp_blog] — exibe o grid público de posts com filtros por categoria
Parâmetros
[srp_blog limite="12" categoria=""]
Uso
Inserir em qualquer página WordPress via editor de blocos ou clássico
Gestor
[srp_blog_manager] — painel de criação/edição de posts (requer login)
Uso
Inserir em página restrita (ex.: “Área do Editor”) — exibe tela de login automática
Post Individual
Rota automática via rewrite rule — não requer shortcode
URL
/blog/{slug-do-post}
Usuários e senhas do gestor frontend
| Usuário (slug) | Nome Exibido | Senha Atual | Autor Padrão | Gênero |
|---|---|---|---|---|
| maura | Maura Lídia | 0118 | Maura Lídia do Vale | f |
| michel | Michel | 2882 | Michel Lima | m |
Credenciais do painel admin WordPress
O painel administrativo (wp-admin > Blog SRP) usa autenticação nativa do WordPress. Requer usuário com papel Administrator (manage_options). Não há senhas customizadas nesta camada.
03Erros Críticos — Impedem Funcionamento
O arquivo define $post na linha 11, mas em seguida usa $srp_post em todas as demais referências (18 ocorrências). $srp_post nunca é definida — PHP 8 lança TypeError fatal; PHP 7 gera Notice e retorna null, quebrando a renderização. Nenhum post individual pode ser exibido.
…
16 $cat_ids = array_filter( explode( ‘,’, $srp_post->categoria_ids ) ); // ← $srp_post não existe!
22 add_action( ‘wp_head’, function() use ( $post, $site_name ) {
23 $srp_post->imagem_destaque … // ← $srp_post não capturada no use()
11 $srp_post = SRP_Blog_DB::get_post_by_slug( sanitize_text_field( $slug ) );
// E corrigir o closure do add_action para capturar $srp_post:
22 add_action( ‘wp_head’, function() use ( $srp_post, $site_name ) {
wp_send_json_error() não encerra a execução automaticamente em todas as versões do WordPress (antes do WP 5.5, o segundo parâmetro $status_code é ignorado e não há exit). Mesmo nas versões modernas, omitir return é má prática. Se o nome estiver vazio, o código envia o JSON de erro mas continua executando e tenta atualizar/inserir a categoria com nome vazio.
wp_send_json_error( [ ‘message’ => ‘O nome da categoria é obrigatório.’ ] );
// ← FALTA return; aqui!
}
// execução continua e tenta salvar categoria com nome vazio
wp_send_json_error( [ ‘message’ => ‘O nome da categoria é obrigatório.’ ] );
return;
}
No bloco de criação de novo post, se insert_post() retornar o ID válido, wp_send_json_success() é chamado — mas a execução cai em seguida para o wp_send_json_error() logo abaixo, porque não há return dentro do if ( $new_id ). Isso gera duas respostas JSON ou, no melhor caso, corrompe o output se o WordPress não encerrar imediatamente.
$post = SRP_Blog_DB::get_post_by_id( $new_id );
wp_send_json_success( [ ‘id’ => $new_id, ‘slug’ => $post->slug, ‘action’ => ‘created’ ] );
// ← FALTA return;
}
wp_send_json_error( [ ‘message’ => ‘Erro ao salvar o post.’ ] ); // ← chamado mesmo com sucesso
$post = SRP_Blog_DB::get_post_by_id( $new_id );
wp_send_json_success( [ ‘id’ => $new_id, ‘slug’ => $post->slug, ‘action’ => ‘created’ ] );
return;
}
wp_send_json_error( [ ‘message’ => ‘Erro ao salvar o post.’ ] );
Os métodos insert_post() e insert_category() declaram o tipo de retorno int|false. Union types são suportados apenas a partir do PHP 8.0. O WordPress declara suporte mínimo ao PHP 7.4 — em servidores com PHP 7.x, o plugin causará um Fatal Error na ativação, impedindo completamente a instalação. Este é provavelmente o erro que impede a instalação relatado.
public static function insert_category( string $nome ): int|false { // ← PHP 8.0+ apenas
public static function insert_post( array $data ) {
public static function insert_category( string $nome ) {
// Opção B: usar docblock (sem custo de performance)
/** @return int|false */
public static function insert_post( array $data ) {
Mesmo após corrigir o nome da variável (bug #1), o closure passado para add_action('wp_head', ...) usa a cláusula use($post, $site_name), mas referencia $srp_post dentro do corpo. A variável precisa ser capturada corretamente no use().
$srp_post->imagem_destaque // mas usa $srp_post — não definida no escopo
} );
$img = $srp_post->imagem_destaque ? …
} );
04Avisos — Problemas que Prejudicam o Funcionamento
O elemento <div id="srpAdminToasts"> é gerado em duas funções diferentes que podem coexistir no mesmo carregamento de página (ao navegar entre páginas do admin, o WP carrega as funções todas). IDs duplicados são inválidos no HTML e causam comportamento imprevisível no JavaScript que busca o toast container.
id="srpAdminToastsCats" e ajustar a referência no JS de categorias.Quando a senha é encontrada, wp_send_json_success() é chamado dentro do foreach, mas sem return. O WordPress encerra a execução via exit internamente nessa função, portanto na prática funciona — mas é uma prática problemática: em testes unitários (onde exit pode ser interceptado) ou refatorações futuras, o loop continuaria iterando e poderia chamar wp_send_json_error() em seguida.
// … configura sessão …
wp_send_json_success( […] );
return; // ← adicionar
}
As senhas '0118' e '2882' estão em texto puro dentro de uma constante PHP definida no arquivo principal do plugin. Qualquer acesso ao sistema de arquivos do servidor expõe essas credenciais diretamente. Além disso, não há mecanismo de expiração ou troca de senha pelo painel.
wp_options com hashing via wp_hash_password(). Criar uma página de configuração no admin para alterar as senhas sem editar código.O editor rich text do gestor frontend usa document.execCommand('bold'), execCommand('foreColor'), etc. Essa API foi marcada como depreciada pelo W3C e pode ser removida em versões futuras de navegadores. Atualmente ainda funciona em todos os browsers, mas é tecnicamente obsoleta.
session_start() é chamado no método render_manager() e também no topo de blog-manager.php. Em ambientes com caching (como WP Super Cache ou LiteSpeed Cache) ou com headers já enviados por outro plugin, session_start() pode falhar silenciosamente ou lançar um warning de “headers already sent”. A verificação if (!session_id()) já existe, o que é boa prática, mas o risco permanece.
init) em vez de chamá-lo dentro do shortcode. Verificar compatibilidade com plugins de caching ativos no servidor.Chamadas como date('d/m/Y', strtotime(...)) usam o timezone padrão do PHP (date_default_timezone_get()), que pode não coincidir com o timezone configurado no WordPress (Settings > General > Timezone). Isso pode exibir datas com diferença de horas.
date( ‘d/m/Y’, strtotime( $p->data_publicacao ) )
// Por:
get_date_from_gmt( $p->data_publicacao, ‘d/m/Y’ )
05Incompatibilidades de Versão
Já detalhado no Crítico #4. O cabeçalho do plugin não contém Requires PHP: 8.0, então o WordPress não bloqueia a ativação em PHP 7.x, resultando em fatal error silencioso que impede qualquer uso.
* Requires PHP: 8.0 ao cabeçalho de srp-blog.php, OU remover os union types para suportar PHP 7.4+.Arrow functions (fn($x) => ...) são usadas extensivamente em todo o plugin. Elas requerem PHP 7.4+, que é o mínimo atual do WordPress. Isso é compatível, mas é bom documentar que o plugin não suporta versões anteriores.
wp_send_json_error(['message'=>'...'], 401) usa o segundo parâmetro (HTTP status code) introduzido no WordPress 4.1. Em instalações muito antigas isso é ignorado, mas não causa erro — apenas o código HTTP retorna 200 ao invés de 401.
06Análise do Banco de Dados
Tabelas criadas pelo plugin
- ✅{prefix}srp_blog_categories — tabela de categorias com
id,nome,slug(UNIQUE),criado_em. Estrutura correta. - ✅{prefix}srp_blog_posts — tabela de posts com
id,titulo,slug(UNIQUE),resumo,conteudo(LONGTEXT),categoria_ids(CSV),autor,imagem_destaque,data_publicacao,status,criado_em,atualizado_em. Índices criados emstatus,slugedata_publicacao. - ✅dbDelta() é usado corretamente para criar/atualizar as tabelas, o que garante idempotência na ativação e upgrade.
- ✅Upgrade automático via hook
plugins_loadedcompara a versão salva emwp_optionscom a constante do plugin — correto. - ⚠️categoria_ids como CSV — armazenar IDs de categorias em texto separado por vírgula (
"1,3,5") é funcional mas não normalizado. Funciona comFIND_IN_SET()no MySQL, mas prejudica performance em grandes volumes. Aceitável para blogs de baixo tráfego. - ✅Sanitização — todos os inputs passam por
sanitize_text_field(),sanitize_textarea_field(),wp_kses_post()ouesc_url_raw()antes de ir ao banco. Correto e seguro. - ✅Queries preparadas — uso consistente de
$wpdb->prepare()em todos os SELECTs com parâmetros. Sem risco de SQL injection. - ✅Deleção de categoria — ao excluir uma categoria, o código remove o ID de
categoria_idsde todos os posts vinculados. Integridade referencial mantida manualmente.
07Análise das Ações AJAX
Mapa de ações registradas
| Ação AJAX | Handler | Auth | Status |
|---|---|---|---|
srp_blog_login | handle_login() | Nonce apenas | ⚠ return ausente |
srp_blog_logout | handle_logout() | Nenhuma | ✓ OK |
srp_blog_save_post | handle_save_post() | Nonce + sessão | ⛔ return ausente |
srp_blog_delete_post | handle_delete_post() | Nonce + sessão | ✓ OK |
srp_blog_get_post | handle_get_post() | Nonce apenas | ✓ OK |
srp_blog_get_posts | handle_get_posts() | Nonce apenas | ✓ OK |
srp_blog_save_cat | handle_save_cat() | Nonce + sessão | ⛔ return ausente |
srp_blog_delete_cat | handle_delete_cat() | Nonce + sessão | ✓ OK |
srp_blog_get_cats | handle_get_cats() | Nonce apenas | ✓ OK |
srp_blog_upload_image | handle_upload_image() | Nonce + sessão | ✓ OK |
srp_blog_upload_html | handle_upload_html() | Nonce + sessão | ✓ OK |
srp_blog_download_post | handle_download_post() | Nonce + sessão | ✓ OK |
srp_blog_admin_delete | handle_admin_delete() | Nonce + manage_options | ✓ OK |
srp_blog_admin_status | handle_admin_status() | Nonce + manage_options | ✓ OK |
'srp_blog_nonce' para ações do frontend, 'srp_blog_admin_nonce' para ações exclusivas do admin WP. Os objetos JS localizados são srpBlogData (frontend) e srpBlogAdmin (admin). O admin recebe ambos os nonces (nonce e fnonce).
08Resumo e Ordem de Correção
Correções obrigatórias (por ordem de prioridade)
-
🔴
[Fix #4 — PRIMEIRO] Remover ou substituir union types
int|falseemclass-db.php. Este é o erro que impede a instalação em PHP 7.x. Adicionar* Requires PHP: 8.0ao cabeçalho se preferir manter a sintaxe. -
🔴
[Fix #1 + #5] Em
blog-single.php: renomear a variável da linha 11 de$postpara$srp_post, e atualizar ouse($post, ...)do closure na linha 22 parause($srp_post, ...). -
🔴
[Fix #2] Em
class-ajax.php, métodohandle_save_cat(): adicionarreturn;após owp_send_json_error()da validação de nome vazio. -
🔴
[Fix #3] Em
class-ajax.php, métodohandle_save_post(): adicionarreturn;dentro do blocoif ($new_id), antes que a execução caia nowp_send_json_error(). -
🟡
[Fix #6] Em
class-ajax.php, métodohandle_login(): adicionarreturn;apóswp_send_json_success()dentro doforeach. -
🟡
[Fix #7] Em
admin-page.php: renomear o segundoid="srpAdminToasts"para algo único e atualizar a referência correspondente no JS. -
🟢
[Opcional] Migrar senhas para
wp_optionscom hash. Substituirdate()porget_date_from_gmt(). Testar compatibilidade dosession_start()com o plugin de cache ativo no servidor.
O que está correto e não precisa ser alterado
- ✅Estrutura de tabelas do banco de dados e uso de
dbDelta() - ✅Sanitização de inputs e uso de
$wpdb->prepare() - ✅Verificação de nonces em todas as ações AJAX
- ✅Rewrite rules para
/blog/{slug}com flush seguro - ✅Enfileiramento condicional de assets (só carrega onde necessário)
- ✅Lógica de slug único com deduplicação automática
- ✅Template
blog-manager.phpeblog-public.phpsem erros - ✅JS admin e frontend sem erros de sintaxe
- ✅CSS admin e frontend sem problemas