O plugin Brasil de Sabores – Receitas é o núcleo funcional do projeto editorial e comunitário do site. Ele concentra a estrutura de conteúdo, os endpoints REST, o painel do usuário, a moderação administrativa e a importação em lote de receitas via JSON.
A proposta dessa arquitetura é manter o WordPress como base principal da operação, usando CPTs, taxonomias, metadados e rotas próprias para dar suporte ao catálogo regional de receitas brasileiras.
brasil-de-sabores-receitas.phpEste é o arquivo principal do plugin. Ele registra o plugin no WordPress e centraliza o carregamento dos módulos internos por meio de require_once.
Declarar nome, descrição, versão e autor do plugin.
Proteger o arquivo contra acesso direto com ABSPATH.
Carregar os módulos:
cpt-taxonomias-rest.php
painel-usuario.php
moderacao-admin.php
importador-json.php
Esse arquivo deve permanecer simples e servir como ponto de entrada do plugin. Toda regra de negócio deve ficar distribuída nos arquivos de includes.
cpt-taxonomias-rest.phpEste arquivo é a camada estrutural central do plugin. Ele define os tipos de conteúdo, taxonomias, metacampos e endpoints REST usados pelo frontend e pelos módulos internos.
Registrar o CPT receita.
Registrar o CPT tema_regiao.
Registrar as taxonomias regiao e subcategoria.
Registrar metadados da receita com suporte à REST API.
Expor endpoints REST públicos e autenticados.
receitaRepresenta a receita individual publicada no site, com URL própria, conteúdo indexável e metadados culinários.
tema_regiaoRepresenta o conteúdo editorial de apoio para uma região, como texto introdutório, banner e contexto cultural.
regiaoTaxonomia hierárquica compartilhada entre receitas e temas regionais. Organiza o conteúdo por Norte, Nordeste, Centro-Oeste, Sudeste e Sul.
subcategoriaTaxonomia hierárquica usada para classificar a receita por tipo de prato ou agrupamento temático.
link_original
tempo_preparo
rendimento
dificuldade
ingredientes
modo_preparo
total_visualizacoes
total_favoritos
bds_status_editorial
motivo_rejeicao
GET
/wp-json/bds/v1/regiao/{slug}Retorna os dados da região, tema editorial, novidades e receitas mais acessadas.
GET
/wp-json/bds/v1/sorteioRetorna uma receita aleatória, com filtro opcional por região e subcategoria.
POST
/wp-json/bds/v1/favoritarAdiciona ou remove uma receita da lista de favoritos do usuário autenticado.
GET
/wp-json/bds/v1/receita/{id}Retorna o payload completo de uma receita individual para uso em single ou frontend dinâmico.
Os campos ingredientes e modo_preparo foram registrados como arrays com schema REST explícito, o que melhora a consistência da API e reduz ambiguidade na leitura dos dados.
O arquivo também foi preparado para lidar com dados antigos eventualmente salvos como JSON string, mantendo compatibilidade durante a transição.
painel-usuario.phpEste arquivo é a camada comunitária do plugin. Ele controla autenticação, área do usuário, favoritos e envio de receitas pela comunidade.
Registrar o shortcode Salve receitas favoritas, envie novas receitas e acompanhe sua participação na comunidade. .developer.wordpressEntrar ou criar conta
Exibir login e cadastro para visitantes.
Exibir painel interno para usuários autenticados.
Permitir edição da conta.
Listar favoritos do usuário.
Listar receitas enviadas pelo próprio usuário.
Receber novas receitas enviadas pela comunidade.
Entrar ou criar conta
Salve receitas favoritas, envie novas receitas e acompanhe sua participação na comunidade.
Renderiza toda a interface pública do painel do usuário em uma página do WordPress.developer.wordpress+1
Permite atualizar nome, e-mail e senha do usuário autenticado.
Lista as receitas que o usuário salvou como favoritas.
Exibe o formulário comunitário de submissão de receita com imagem, taxonomias e metadados principais.
Lista as receitas enviadas pelo próprio usuário e mostra o status editorial atual.
Quando o usuário envia uma nova receita:
o post é criado no CPT receita;
a receita entra com post_status =;
pending
a meta bds_status_editorial recebe o valor pendente;
a imagem é enviada como featured image;
o conteúdo segue para moderação administrativa.
A autenticação do login foi ajustada para funcionar por e-mail de forma mais previsível, localizando o usuário e depois executando wp_signon() com o login real.
Os campos ingredientes e modo_preparo são salvos como arrays, alinhados ao registro estrutural do plugin.
moderacao-admin.phpEste arquivo é a camada editorial administrativa do plugin. Ele controla a revisão das receitas enviadas pela comunidade antes da publicação definitiva.
Registrar a página de moderação no admin do CPT receita.
Listar receitas pendentes ou aguardando ajustes.
Aprovar e publicar receitas.
Solicitar ajustes ao autor.
Rejeitar editorialmente uma submissão.
Registrar motivo de revisão ou rejeição.
pendingStatus inicial da receita enviada pelo usuário, aguardando revisão.
needs_revisionStatus customizado usado para receitas que precisam de ajustes antes da publicação. Esse tipo de status pode ser registrado com register_post_status() no WordPress.developer.wordpress
draft + bds_status_editorial
= rejeitadoUsado quando a equipe editorial decide reprovar a receita, mas quer manter o histórico da submissão.
publishUsado quando a receita é aprovada e publicada.
Receita enviada entra como pendente.
Moderador pode aprovar e publicar.
Moderador pode solicitar ajustes e devolver ao fluxo editorial.
Moderador pode rejeitar com justificativa salva em meta.
bds_status_editorial
motivo_rejeicao
Esse arquivo substitui a lógica fraca de “rejeitar = lixeira” por um fluxo editorial mais rastreável e mais útil para o projeto.
A tela administrativa pode carregar assets específicos com admin_enqueue_scripts condicionado à página de moderação, o que é o padrão mais adequado para esse tipo de interface no admin.
importador-json.phpEste arquivo é a camada de ingestão administrativa do plugin. Ele permite importar receitas em lote por meio de um arquivo JSON estruturado.
Registrar a página administrativa de importação JSON.
Ler um arquivo JSON com array de receitas.
Importar uma receita por chamada AJAX.
Evitar duplicatas.
Criar ou associar taxonomias automaticamente.
Baixar imagem remota e associar ao post.
Registrar dados de auditoria da importação.
Se a receita já existir, o item não é importado novamente.
Se a receita já existir, os dados existentes são atualizados.
A busca por duplicata segue esta ordem:
link_original
slug
titulo
Cada item do array pode conter:
titulo
slug
descricao
regiao
subcategoria
ingredientes
modo_preparo
tempo_preparo
rendimento
dificuldade
imagem_url
link_original
Quando imagem_url estiver presente, o sistema tenta baixar a imagem automaticamente e definir o arquivo como imagem destacada da receita. Esse fluxo pode ser implementado com media_handle_sideload() após o download do arquivo remoto.developer.wordpress+1
bds_origem_importacao
bds_data_importacao
bds_importado_por
bds_slug_importado
O processamento está organizado item por item via AJAX, o que reduz risco de timeout em lotes médios e deixa o MVP mais seguro operacionalmente.
O campo bds_status_editorial padroniza o estado editorial da receita dentro do projeto.
Valores previstos:
pendente
publicado
em_revisao
rejeitado
rascunho
O campo motivo_rejeicao armazena a justificativa da equipe quando uma receita precisa de ajustes ou é rejeitada. Apesar do nome, ele também pode guardar observações de revisão.
Os campos ingredientes e modo_preparo devem ser tratados como arrays estruturados, e não como texto único ou JSON solto.
Usuário entra no site.
Escolhe uma região.
Navega pelas receitas.
Abre a single da receita.
Pode favoritar o conteúdo se estiver autenticado.
Usuário cria conta ou faz login.
Envia uma receita pelo painel.
A receita entra como pendente.
A equipe revisa no admin.
A receita é publicada, devolvida para ajustes ou rejeitada.
Admin acessa a tela de importação.
Envia um JSON estruturado.
O sistema cria ou atualiza receitas.
Taxonomias são ajustadas.
A imagem destacada é baixada quando disponível.
Criar os templates públicos da home, região e single.
Conectar os endpoints REST ao carregamento dinâmico da home.
Adicionar JavaScript e CSS definitivos para o painel.
Permitir edição de receita devolvida para ajustes.
Incluir filtros por status, autor e região.
Adicionar histórico editorial por receita.
Suportar lotes maiores com processamento em blocos.
Adicionar relatório final mais detalhado da importação.
=======================================================
assets/js/user-recipes.jsEste arquivo é a camada JavaScript do painel do usuário no frontend. Ele conecta os formulários renderizados por painel-usuario.php às rotas AJAX e REST do plugin, fazendo o painel realmente funcionar no navegador, sem dependência de jQuery ou bibliotecas externas.
Alternar abas de autenticação entre login e cadastro.
Alternar abas do painel do usuário autenticado (conta, favoritos, enviar receita, minhas receitas).
Enviar login por AJAX.
Enviar cadastro por AJAX.
Atualizar dados da conta por AJAX.
Enviar nova receita por AJAX com FormData, incluindo upload de imagem.
Carregar favoritos do usuário sob demanda.
Carregar a lista de receitas enviadas pelo usuário sob demanda.
Permitir remover favoritos diretamente da listagem de favoritos.
Favoritar/desfavoritar receitas fora do painel, em qualquer botão .bds-favorito-btn[data-receita-id] presente na página.
Este arquivo depende de:
HTML produzido por painel-usuario.php;
classes e atributos como .bds-aba, .bds-painel-aba, [data-aba-conteudo], [data-painel-conteudo] e .bds-form__msg;
admin-ajax.php exposto ao frontend;developer.wordpress+1
objeto global bdsUserPanel, localizado via wp_localize_script(), que é o padrão recomendado para passar ajaxUrl e demais parâmetros dinâmicos ao JavaScript.dev+1
O script implementa três formas de comunicação, cada uma para um tipo de payload:
post(): monta URLSearchParams e envia como application/x-www-form-urlencoded para admin-ajax.php, usado em login, cadastro, conta, favoritos e minhas receitas.codingace+1
postFormData(): monta um FormData a partir do próprio <form>, usado exclusivamente no envio de receita, pois preserva o upload de arquivo sem serialização manual.developer.wordpress
fetch() direto para a rota REST /bds/v1/favoritar, autenticado via header X-WP-Nonce, que é a forma padrão de autenticação por cookie na REST API do WordPress.developer.wordpress+1
Todas as chamadas usam credentials: para garantir que os cookies de sessão do WordPress sejam enviados corretamente.stackoverflow
'same-origin'
initAbasAuth() alterna entre login e cadastro na tela de visitante, e initAbasPainel() alterna entre conta, favoritos, envio de receita e minhas receitas no painel autenticado, sem recarregar a página.
O formulário #bds-form-login envia email, senha, action=bds_login e nonce para o backend via post(). Em caso de sucesso, a página é recarregada para exibir o painel autenticado.
O formulário #bds-form-cadastro envia nome, email, senha, action=bds_cadastro e nonce. Em caso de sucesso, a página recarrega com o usuário já autenticado.
O formulário #bds-form-conta envia nome, email, nova senha opcional e nonce. Após sucesso, a mensagem é exibida no próprio formulário e o campo de senha é limpo.
O formulário #bds-form-enviar-receita envia todos os campos, inclusive o arquivo de imagem, usando postFormData(), o que permite upload de mídia sem serialização manual do formulário.developer.wordpress
A aba de favoritos é carregada sob demanda, apenas na primeira vez que o usuário a abre, via carregarFavoritos(). O script monta os cards com base no retorno do backend, cobre os estados de carregando, vazio e erro, e liga os botões de desfavoritar de cada card.
A aba “Minhas receitas” também é carregada sob demanda, via carregarMinhasReceitas(), usando a resposta AJAX para montar a listagem com status editorial, rótulo amigável e eventual feedback de moderação.
initFavoritarBotoesGlobais() liga qualquer botão .bds-favorito-btn[data-receita-id] fora da lista de favoritos (por exemplo, na single da receita) à mesma lógica de toggle usada no painel.
toggleFavorito() tenta primeiro a rota REST /bds/v1/favoritar, enviando o nonce no header X-WP-Nonce. Se essa chamada falhar por qualquer motivo — rede, CORS, indisponibilidade —, o script cai automaticamente para o endpoint AJAX bds_favoritar_fallback via admin-ajax.php, garantindo que o recurso de favoritar continue funcionando mesmo sem a REST API disponível.developer.wordpress+1
O script espera ser localizado com um objeto assim:
phpwp_localize_script( 'bds-user-recipes', 'bdsUserPanel',array('ajaxUrl' => admin_url( 'admin-ajax.php' ),'restFavoritarUrl' => rest_url( 'bds/v1/favoritar' ),'wpRestNonce' => wp_create_nonce( 'wp_rest' ),'favoritosNonce' => wp_create_nonce( 'bds_painel_usuario_nonce' ),'strings' =>array('erroGenerico' => 'Ocorreu um erro ao processar a solicitação.','carregando' => 'Carregando...','semFavoritos' => 'Você ainda não salvou nenhuma receita.','semReceitas' => 'Você ainda não enviou nenhuma receita.',),) );
O uso de wp_localize_script() para expor ajaxUrl e demais parâmetros dinâmicos ao JavaScript continua sendo uma prática amplamente adotada em plugins WordPress, embora a documentação oficial mais recente recomende wp_add_inline_script() para dados que não são strings de tradução; ambas as abordagens funcionam de forma equivalente para este caso.wordpress.stackexchange+1
O carregamento de favoritos e de “minhas receitas” foi desenhado em modo lazy — só ocorre quando a aba correspondente é aberta pela primeira vez, controlado por dataset.carregado. Isso reduz requisições desnecessárias e deixa o carregamento inicial do painel mais leve.
As mensagens de retorno de login, cadastro, conta e envio de receita são mostradas dentro do próprio formulário, no elemento .bds-form__msg, mantendo o feedback no contexto da ação realizada.
O botão de favoritar alterna a classe .ativo e o texto (“Favoritar” / “Remover favorito”) com base na resposta do backend, e, quando usado dentro da lista de favoritos, remove o card da tela e exibe o estado vazio se a lista ficar sem itens.
Para que o botão de favoritos funcione plenamente no fallback, o plugin precisa registrar a action wp_ajax_bds_favoritar_fallback apontando para ajax_favoritar_fallback() — essa função e o hook já foram implementados no painel-usuario.php durante esta revisão.
O nome do nonce usado em favoritosNonce e nos handlers ajax_listar_favoritos(), ajax_minhas_receitas() e ajax_favoritar_fallback() precisa ser idêntico entre geração (wp_create_nonce()) e verificação (check_ajax_referer()); o padrão adotado neste plugin é bds_painel_usuario_nonce.developer.wordpress+1
É importante enfileirar este arquivo, junto com Salve receitas favoritas, envie novas receitas e acompanhe sua participação na comunidade.dashboard.css, apenas nas páginas onde o shortcode estiver presente, para evitar carregar JS e CSS desnecessários em outras páginas do site.Entrar ou criar conta
====================================================================
assets/css/dashboard.cssEste arquivo é a camada visual do painel do usuário no frontend. Ele estiliza autenticação, navegação por abas, formulários, cards de favoritos, listagem de receitas enviadas e mensagens de estado, mantendo uma interface de web app compacta e clara.
Estilizar a área de login e cadastro.
Estilizar o painel do usuário autenticado.
Definir visual das abas de navegação do painel.
Padronizar botões, links de ação e estados ativos.
Estruturar formulários de conta e envio de receita.
Exibir mensagens de sucesso, erro, vazio e carregamento.
Organizar cards de favoritos e lista de “minhas receitas”.
Garantir comportamento responsivo em mobile, tablet e desktop.
O CSS segue uma abordagem de painel administrativo leve: tipografia compacta, superfícies neutras, um único acento principal e densidade equilibrada. Em interfaces desse tipo, a recomendação é usar títulos contidos, labels curtos, feedback inline e layout eficiente, sem escalas tipográficas grandes nem efeitos teatrais.
.bds-auth-wrap e .bds-auth-boxAgrupam e estilizam a área de visitantes, com foco em login e cadastro.
.bds-painelÉ o contêiner principal do painel autenticado. Recebe superfície, borda, raio e sombra base.
.bds-abas e .bds-painel-abasControlam a faixa de navegação por abas. Os botões ativos usam contraste alto e os inativos mantêm leitura discreta.
.bds-formPadroniza os formulários com grid, espaçamento e campos consistentes.
.bds-cards-grid e .bds-cardEstruturam a visualização de favoritos em cards responsivos.
.bds-minhas-lista e .bds-minha-receitaOrganizam a listagem das receitas enviadas pelo usuário com status editorial e ações rápidas.
O arquivo define blocos específicos para:
.bds-form__msg.erro e .bds-erro;
.bds-form__msg.sucesso e .bds-sucesso;
.bds-loading;
.bds-vazio.
Essa abordagem segue a boa prática de tratar loading, empty e error como estados projetados da interface, e não como conteúdo improvisado.
Em mobile, os botões de abas e ações passam a ocupar largura total, as ações ficam empilhadas e o painel prioriza leitura em uma coluna. Em telas médias e grandes, entram grids de duas colunas para formulários e cards, além de uma composição mais larga para receitas e resumos.
O CSS inclui foco visível, áreas clicáveis confortáveis e altura mínima de 44px para botões e ações principais, alinhando o painel às recomendações para interfaces web e navegação por toque.
Este arquivo deve ser enfileirado junto do assets/js/user-recipes.js, de preferência somente na página onde o shortcode do painel estiver presente.
===========================================================
Esse trecho adiciona ao painel-usuario.php a responsabilidade de registrar e carregar os assets do painel do usuário no frontend, conectando o HTML do shortcode com o CSS dashboard.css e o JavaScript user-recipes.js.developer.wordpress+1
Registrar o CSS do painel com wp_register_style().developer.wordpress
Registrar o JavaScript do painel com wp_register_script().developer.wordpress
Carregar os assets apenas quando o shortcode é renderizado.wpexplorer+1
Passar ajaxUrl, URL REST e nonces para o JavaScript via wp_localize_script().developer.wordpress+1
Expor o nonce wp_rest para chamadas autenticadas à REST API.medium
Expor um nonce próprio do painel para fallbacks AJAX tradicionais.developer.wordpress
registrar_assets()Registra os arquivos assets/css/dashboard.css e assets/js/user-recipes.js no frontend, sem necessariamente enfileirá-los naquele momento.developer.wordpress+1
enqueue_assets()Enfileira os assets já registrados e injeta no script o objeto global bdsUserPanel, contendo URLs e nonces necessários para o funcionamento do painel.developer.wordpress+1
render_shortcode()Renderiza o conteúdo do shortcode Salve receitas favoritas, envie novas receitas e acompanhe sua participação na comunidade. e chama Entrar ou criar conta
enqueue_assets() no momento em que o painel realmente é usado na página. Essa estratégia evita carga desnecessária em outras páginas do site.sanjeebaryal.com+1
O objeto bdsUserPanel enviado ao frontend contém:
ajaxUrl, apontando para admin-ajax.php;medium
restFavoritarUrl, apontando para a rota REST de favoritos;medium
wpRestNonce, para autenticação REST no header X-WP-Nonce;medium
favoritosNonce, para fallback AJAX tradicional;developer.wordpress
mensagens auxiliares em strings.developer.wordpress
Evita carregar assets do painel no site inteiro.wpexplorer+1
Mantém o shortcode autocontido.sanjeebaryal.com
Centraliza os parâmetros dinâmicos do frontend em um único objeto JavaScript.developer.wordpress
Deixa o painel preparado para conviver com AJAX clássico e REST API.
==========================================================
ajax_cadastro()Cria uma nova conta de usuário a partir do formulário público do painel, valida os campos e autentica o usuário automaticamente após o cadastro.developer.wordpress
Validar o nonce do cadastro.developer.wordpress
Validar nome, e-mail e senha.developer.wordpress
Impedir cadastro com e-mail duplicado.developer.wordpress
Gerar um user_login com base no e-mail, evitando conflito de usernames.developer.wordpress
Criar o usuário com papel subscriber.developer.wordpress
Autenticar o usuário após o cadastro.developer.wordpress
ajax_login()Executa o login do usuário a partir do formulário público do painel, buscando primeiro o usuário pelo e-mail e autenticando com wp_signon().developer.wordpress
Validar o nonce do login.developer.wordpress
Validar e-mail e senha.developer.wordpress
Buscar o usuário pelo e-mail informado.developer.wordpress
Autenticar via wp_signon().developer.wordpress
Retornar resposta JSON para o frontend.
ajax_atualizar_conta()Atualiza os dados da conta do usuário autenticado a partir do painel frontend, permitindo alterar nome, e-mail e senha sem ir ao wp-admin.developer.wordpress
Validar o nonce da requisição AJAX.developer.wordpress
Garantir que exista uma sessão autenticada válida.developer.wordpress
Validar nome e e-mail informados.developer.wordpress
Evitar conflito com e-mail já usado por outra conta.core.trac.wordpress
Atualizar senha apenas quando o campo for preenchido.developer.wordpress
Persistir os dados via wp_update_user().developer.wordpress
Ao enviar user_pass no array de atualização, o WordPress trata o hash internamente. Em mudanças de senha do usuário atual, o fluxo de autenticação pode ser afetado, por isso a revalidação da sessão após a atualização ajuda a manter a experiência estável no painel.wp-kama+1
ajax_enviar_receita()Recebe a submissão de uma nova receita enviada pelo usuário autenticado no frontend, cria o post no CPT receita, associa taxonomias e metadados e envia a imagem destacada para a biblioteca de mídia.developer.wordpress+1
Validar o nonce da submissão AJAX.developer.wordpress
Garantir que o usuário esteja autenticado.developer.wordpress
Sanitizar os campos textuais e URLs da receita.make.xwp
Transformar ingredientes e modo de preparo em arrays por linha.make.xwp
Criar a receita com status pending.make.xwp
Associar regiao e subcategoria à nova receita.make.xwp
Salvar os principais metacampos editoriais e culinários.make.xwp
Fazer upload da imagem com media_handle_upload().wp-kama+1
Definir a imagem destacada do post.wordpress.stackexchange
Notificar o administrador por e-mail sobre a nova submissão.developer.wordpress
No frontend WordPress, media_handle_upload() exige a inclusão explícita dos arquivos image.php, file.php e media.php antes do upload. Sem isso, a função pode falhar fora do wp-admin.
ajax_listar_favoritos()Ela valida login, verifica o nonce com check_ajax_referer(), lê os favoritos via get_user_meta() e retorna a resposta com wp_send_json_success() ou wp_send_json_error(), que são o padrão recomendado para handlers AJAX no WordPress.wordpress+2
Na montagem do payload, get_the_post_thumbnail_url() é apropriada para devolver a URL da imagem destacada, e get_permalink() entrega a URL pública da receita para o card do painel.developer.wordpress
O JavaScript vai receber algo neste formato:
json{"success": true,"data": {"items": [{"id": 15,"titulo": "Baião de dois","link": "https://site.com/receita/baiao-de-dois","imagem": "https://site.com/uploads/baiao.jpg","descricao": "Receita tradicional nordestina...","tempo_preparo": "45 min","rendimento": "4 porções","dificuldade": "Fácil","regiao": "Nordeste","subcategoria": "Prato principal","favoritado": true}],"total": 1}}
O formato success/data vem automaticamente de wp_send_json_success(), então no JS o correto é acessar response.data.items e response.data.total.wp-kama+1
Você também precisa garantir estes hooks:
phpadd_action( 'wp_ajax_bds_listar_favoritos',array( $this, 'ajax_listar_favoritos' ) );
Como essa ação depende de usuário autenticado, normalmente não faz sentido registrar wp_ajax_nopriv_* para ela. O padrão WordPress separa mesmo ações autenticadas em wp_ajax_* e ações públicas em wp_ajax_nopriv_*.wordpress
Se no seu plugin os favoritos estiverem salvos com outro meta key, por exemplo favoritos_receitas ou _bds_favoritos, basta trocar 'bds_favoritos' na função.
Se quiser, no próximo passo eu monto também o user-recipes.js que consome esse endpoint e renderiza os cards de favoritos no painel.
A ajax_minhas_receitas() retorna dados já prontos para renderização no dashboard, inclusive status_label, feedback, imagem e links, o que reduz processamento no JavaScript.developer.wordpress
Já a ajax_favoritar_fallback() serve como redundância útil quando o fluxo REST não estiver disponível no frontend, mantendo atualização segura via nonce, get_user_meta() e update_user_meta().developer.wordpress+1
O ponto mais pesado aqui é contar_total_favoritos_receita(), porque ele percorre usuários para recalcular a contagem. Para MVP funciona bem, mas em escala maior vale migrar para atualização incremental desse meta ou para uma tabela própria de favoritos.
templates/single-receita.phpEste template renderiza a página pública individual de cada receita, com conteúdo completo, ingredientes, modo de preparo, imagem, fonte e dados estruturados Recipe em JSON-LD, sendo estratégico para indexação orgânica no Google.
Carregar e normalizar os metacampos da receita (ingredientes, modo_preparo, tempo_preparo, rendimento, dificuldade, link_original).
Incrementar total_visualizacoes a cada carregamento da página.
Montar o schema Recipe em JSON-LD com name, image, description, recipeIngredient, recipeInstructions, recipeYield, recipeCategory, recipeCuisine e totalTime.karpi
Exibir breadcrumb, taxonomia de região, chips de metadados, botão de favoritar e conteúdo completo da receita.
Listar receitas relacionadas da mesma região na barra lateral.
O Google exige apenas name e image no nível da página para elegibilidade de rich results de receita, mas recomenda fortemente recipeIngredient, recipeInstructions, prepTime, cookTime, totalTime, recipeYield, recipeCategory e recipeCuisine para melhorar a exibição nos resultados de busca. Cada passo do modo de preparo é representado como um objeto HowToStep com a propriedade text, seguindo o padrão recomendado pela Schema.org.schema+1
Os campos ingredientes e modo_preparo podem ter sido salvos como array estruturado, JSON string ou texto quebrado por linha, dependendo da origem (formulário, importação ou dados legados). O template trata as três possibilidades antes de renderizar, evitando páginas quebradas.
O botão de favoritar exibe estado visual diferente quando a receita já está salva pelo usuário autenticado, e sinaliza com data-requer-login quando o visitante não está logado, para que o JavaScript do painel (favorites.js) trate o redirecionamento ou o aviso de login.
A página usa itemscope/itemprop como camada adicional de microdata sobre os elementos visuais, além do JSON-LD, reforçando a leitura semântica do conteúdo pelos mecanismos de busca.
assets/css/single.cssEste arquivo estiliza a página pública individual da receita, cobrindo breadcrumb, cabeçalho com metadados, imagem destacada, corpo editorial, lista de ingredientes, passos numerados do preparo, bloco de fonte e sidebar de categorias e receitas relacionadas.
Definir hierarquia visual do título, introdução e chips de metadados da receita.
Estilizar o botão de favoritar com estado ativo e contador.
Organizar a leitura da história, ingredientes e modo de preparo com largura de prosa controlada.
Numerar visualmente os passos do preparo com destaque no acento teal.
Estruturar a sidebar fixa com categorias e receitas relacionadas em telas grandes.
Garantir leitura confortável em mobile, com imagem reduzida e ações em largura total.
O arquivo depende das variáveis já definidas em dashboard.css (--bds-primary, --bds-surface, --bds-radius-*, --bds-space-*, --bds-text-*), garantindo consistência visual entre o painel do usuário e a página pública da receita. Por isso, dashboard.css deve ser carregado antes de single.css, ou os tokens devem ser centralizados em um arquivo compartilhado.
A prosa da história e dos ingredientes é limitada entre 60ch e 68ch para manter conforto de leitura, enquanto o título e a introdução podem ocupar até 75ch, já que texto de destaque é lido de forma diferente do corpo de texto.
A partir de 1024px, a sidebar de categorias e relacionadas fica fixa (position: sticky) enquanto o conteúdo principal rola, ajudando na permanência de navegação sem competir com o conteúdo principal.
cpt-taxonomias-rest.phpEste arquivo é um componente central do plugin “Brasil de Sabores”, responsável por definir a estrutura de conteúdo principal do projeto. Ele registra os Custom Post Types (CPTs) para “Receitas” e “Temas de Região”, as taxonomias para “Regiões” e “Subcategorias”, os metadados associados ao CPT “Receita”, e os endpoints da API REST para interagir com esses dados de forma dinâmica.
O arquivo é dividido em cinco seções principais:
Esta seção é responsável por criar os tipos de conteúdo e as categorias que estruturam o projeto.
initbds_registrar_cpts_e_taxonomias()receitaRepresenta uma receita culinária.
public: true (visível no frontend e no admin).has_archive: true (permite uma página de arquivo para todas as receitas).show_in_rest: true (disponível via API REST).menu_icon: dashicons-carrot (ícone no menu do admin).supports: title, editor (conteúdo principal), thumbnail (imagem destacada), excerpt (resumo), author, custom-fields (para metadados).rewrite: slug => receita (URL amigável: /receita/nome-da-receita).capability_type: post (usa as capacidades padrão de posts).map_meta_cap: true (mapeia capacidades meta para capacidades primitivas).tema_regiaoRepresenta um tema ou região específica, podendo conter informações editoriais sobre ela.
public: false (não visível diretamente no frontend, mas acessível via admin e REST).show_ui: true (visível no painel administrativo).show_in_rest: true (disponível via API REST).supports: title, editor, thumbnail, custom-fields.menu_icon: dashicons-location-alt.regiaoUsada para categorizar receitas e temas de região por localização geográfica.
receita, tema_regiao.hierarchical: true (permite estrutura de árvore, ex: “Norte” > “Amazonas”).show_in_rest: true.show_admin_column: true (exibe a coluna no admin).rewrite: slug => regiao (URL amigável: /regiao/nome-da-regiao).subcategoriaUsada para categorizar receitas por tipo ou subcategoria culinária.
receita.hierarchical: true.show_in_rest: true.show_admin_column: true.rewrite: slug => tipo (URL amigável: /tipo/nome-da-subcategoria).Esta seção registra os metadados personalizados para o CPT receita. register_post_meta() define as propriedades dos metadados, mas não cria a interface de usuário no painel administrativo. Para isso, é necessária uma meta box separada.
initbds_registrar_meta_fields()auth_callback: bds_meta_auth_callback() (requer edit_posts para manipular metadados).link_original: URL da fonte original da receita.
stringesc_url_rawtempo_preparo: Tempo estimado para o preparo da receita.
stringsanitize_text_fieldrendimento: Quantidade de porções ou unidades que a receita rende.
stringsanitize_text_fielddificuldade: Nível de dificuldade da receita (Fácil, Médio, Difícil).
stringsanitize_text_fieldingredientes: Lista de ingredientes.
array (armazenado como array de strings).bds_sanitize_array_strings (converte string JSON ou textarea em array de strings).array de string.modo_preparo: Passos para o preparo da receita.
array (armazenado como array de strings).bds_sanitize_array_strings.array de string.total_visualizacoes: Contador de visualizações da receita.
integerabsinttotal_favoritos: Contador de vezes que a receita foi favoritada.
integerabsintbds_status_editorial: Status editorial da receita (ex: publicado, pendente, rejeitado).
stringsanitize_text_fieldmotivo_rejeicao: Texto explicando o motivo da rejeição editorial.
stringsanitize_textarea_fieldbds_meta_auth_callback(): Verifica se o usuário atual tem permissão para editar posts (edit_posts).bds_sanitize_array_strings( $value ): Sanitiza um valor que pode ser uma string JSON ou um array de strings, garantindo que o resultado seja um array de strings sanitizadas.Esta seção registra as rotas personalizadas da API REST para o plugin, permitindo que aplicações frontend interajam com os dados do Brasil de Sabores.
rest_api_initbds_registrar_rotas_rest()bds/v1GET /regiao/(?P<slug>[a-zA-Z0-9-]+): Retorna detalhes de uma região específica, incluindo informações do tema_regiao associado e listas de receitas (novidades, mais_acessadas).
slug (obrigatório, sanitizado com sanitize_title).__return_true).bds_endpoint_regiao().GET /sorteio: Retorna uma receita aleatória, opcionalmente filtrada por região e/ou subcategoria.
regiao (opcional), subcategoria (opcional).__return_true).bds_endpoint_sorteio().POST /favoritar: Adiciona ou remove uma receita dos favoritos do usuário logado. Atualiza o contador total_favoritos da receita.
post_id (obrigatório, ID da receita).is_user_logged_in()).bds_endpoint_favoritar().GET /receita/(?P<id>\d+): Retorna todos os detalhes de uma receita específica, incluindo metadados e termos de taxonomia.
id (obrigatório, ID da receita).__return_true).bds_endpoint_receita().Implementa a lógica de negócios para cada endpoint REST registrado.
bds_endpoint_regiao( $request ):
regiao pelo slug.tema_regiao associado à região para obter banner e descrição.bds_endpoint_sorteio( $request ):
WP_Query com base nos filtros de regiao e subcategoria fornecidos.rand para retornar uma receita aleatória.bds_endpoint_favoritar( $request ):
post_id é válido e se o usuário está logado.user_meta bds_favoritos).post_id da lista de favoritos.post_meta total_favoritos da receita.bds_endpoint_receita( $request ):
ingredientes, modo_preparo, tempo_preparo, etc.), status de favorito para o usuário logado, e termos de regiao e subcategoria.Funções auxiliares reutilizáveis para consultas e formatação de dados.
bds_query_receitas_por_regiao( $slug_regiao, $args_extra = array() ):
WP_Query para buscar receitas de uma regiao específica.bds_formatar_card_receita( $post ):
WP_Post (ou ID de post) em um array de dados simplificado, ideal para exibição em cards (ID, título, descrição, imagem, link, tempo de preparo, rendimento, dificuldade, região, subcategoria, status de favorito).bds_usuario_favoritou( $user_id, $post_id ):
user_meta bds_favoritos.bds_get_receita_meta_array( $post_id, $meta_key ):
ingredientes ou modo_preparo).bds_formatar_termos( $terms ):
WP_Term) em um array mais simples com id, nome e slug.