Initial commit

This commit is contained in:
2025-09-12 19:05:50 -03:00
commit 6fb90520e4
12 changed files with 1136 additions and 0 deletions

2
.gitattributes vendored Normal file
View File

@@ -0,0 +1,2 @@
# Auto detect text files and perform LF normalization
* text=auto

67
README.md Normal file
View File

@@ -0,0 +1,67 @@
# Gerenciador de Eventos (eventos-manager)
Plugin WordPress para cadastro, gerenciamento e exibição de eventos com calendário interativo, lista de próximos eventos e integração via shortcodes e widget.
## Funcionalidades
- Cadastro de eventos personalizados (CPT: `evento`)
- Metabox para data, hora e local do evento
- Taxonomia personalizada para tipos de evento
- Calendário interativo (FullCalendar.js) com AJAX
- Lista de próximos eventos filtrável por tipo e limite
- Shortcodes para exibição do calendário, lista e widget
- Página única customizada para eventos (`single-evento.php`)
- Widget para exibir próximos eventos na sidebar
- Página de ajuda no admin
## Instalação
1. Faça upload da pasta `eventos-manager` para o diretório `wp-content/plugins/`.
2. Ative o plugin no painel do WordPress.
3. O tipo de post "Evento" estará disponível no menu lateral.
## Shortcodes Disponíveis
- `[mostra-calendario]` — Exibe o calendário de eventos.
- `[mostra-prox-eventos limit="5" tipo=""]` — Lista os próximos eventos. Parâmetros:
- `limit`: número de eventos (padrão: 5)
- `tipo`: slug do tipo de evento (opcional)
- `[eventos-completo]` — Exibe calendário e lista de próximos eventos juntos.
- `[mostra-calendario-widget]` — Exibe um calendário compacto para sidebar ou widgets.
## Widget
- Vá em **Aparência > Widgets** e adicione o widget "Próximos Eventos" à sua sidebar.
- Configure o título e o limite de eventos a exibir.
## Custom Post Type e Taxonomia
- **Post Type:** `evento`
- **Taxonomia:** `tipo_evento` (hierárquica)
## Templates
- O plugin inclui o template `single-evento.php` para exibição individual dos eventos.
## Scripts e Estilos
- FullCalendar.js e Moment.js são carregados automaticamente.
- Estilos customizados para admin e frontend em `/assets/css/`.
## AJAX
- Os eventos do calendário são carregados via AJAX para melhor performance.
## Página de Ajuda
- Acesse em **Eventos > Ajuda** para instruções e exemplos de uso dos shortcodes.
## Autor
Marco Antonio Vivas
---
**Observação:**
- Para personalizações avançadas, edite os arquivos em `includes/` e os templates conforme necessário.
- Compatível com WordPress 5.0+.

57
assets/css/admin.css Normal file
View File

@@ -0,0 +1,57 @@
/* No changes needed, but ensure this file exists as referenced in class-eventos-admin.php */
.evento-metabox {
display: flex;
flex-direction: column;
gap: 15px;
padding: 15px 0;
}
.meta-field {
display: flex;
flex-direction: column;
gap: 5px;
}
.meta-field label {
font-weight: 600;
}
.meta-field input[type="date"],
.meta-field input[type="time"],
.meta-field input[type="text"] {
padding: 8px;
border: 1px solid #ddd;
border-radius: 4px;
max-width: 300px;
}
#eventos-calendario-widget {
min-width: 280px;
min-height: 340px;
font-size: 15px;
max-height: 370px;
overflow: hidden;
border-radius: 18px; /* Mais arredondado */
box-shadow: 0 2px 16px rgba(44,62,80,0.10);
border: none;
background: #fff;
}
#eventos-calendario-widget .fc {
border-radius: 18px;
box-shadow: 0 2px 16px rgba(44,62,80,0.10);
background: #fff;
padding: 16px 8px 8px 8px;
}
#eventos-calendario-widget .fc-day-number {
border-radius: 50%;
}
#eventos-calendario-widget .fc-center h2 {
color: #3498db;
}
#eventos-calendario-widget .fc-today .fc-day-number {
background: #3498db;
color: #fff;
box-shadow: 0 2px 8px rgba(52,152,219,0.15);
}
#eventos-calendario-widget .fc-has-event .fc-day-number {
background: #217dbb;
color: #fff;
border: 2px solid #3498db;
box-shadow: 0 2px 8px rgba(52,152,219,0.15);
}

View File

@@ -0,0 +1,288 @@
/* CSS Mínimo para Estrutura do Gerenciador de Eventos */
.noticias-eventos-wrapper {
display: flex;
gap: 40px;
}
.noticias-col {
flex: 2;
}
.eventos-col {
flex: 1;
min-width: 280px;
display: flex;
flex-direction: column;
gap: 30px;
}
.proximos-eventos-lista {
list-style: none;
padding: 0;
margin: 0;
}
.proximos-eventos-lista li {
display: flex;
align-items: center;
gap: 16px;
margin-bottom: 18px;
}
.evento-titulo a {
text-decoration: none;
}
.evento-tipo {
margin-left: auto;
}
@media (max-width: 900px) {
.noticias-eventos-wrapper {
flex-direction: column;
}
.eventos-col {
min-width: 0;
}
}
/* --- Estilos do Novo Calendário Offline --- */
.em-calendario-wrapper {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
background: #fff;
border: 1px solid #e5e5e5;
border-radius: 8px;
padding: 15px;
box-shadow: 0 2px 5px rgba(0,0,0,0.05);
}
.em-calendario-wrapper[data-view="full"] .em-dia-celula {
height: 100px; /* Aumenta a altura para caber eventos */
}
.em-toolbar {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 15px;
user-select: none;
}
.em-toolbar-section {
display: flex;
align-items: center;
gap: 5px;
}
.em-toolbar-center {
justify-content: center;
flex-grow: 1;
}
.em-toolbar-right {
justify-content: flex-end;
flex-grow: 1;
}
.em-mes-ano {
font-size: 1.2em;
font-weight: 600;
color: #333;
margin: 0;
text-align: center;
flex-grow: 0;
}
.em-nav-btn {
background: #f7f7f7;
border: 1px solid #ccc;
border-radius: 4px;
padding: 5px 10px;
cursor: pointer;
font-weight: bold;
color: #555;
transition: background 0.2s;
}
.em-view-btn {
background: none;
border: none;
font-size: 22px;
cursor: pointer;
}
.em-nav-btn:hover {
background: #e9e9e9;
}
.em-today-btn {
font-weight: normal;
padding: 5px 12px;
}
.em-dias-semana, .em-dias-grid {
display: grid;
grid-template-columns: repeat(7, 1fr);
text-align: center;
}
.em-dias-semana span {
font-weight: 600;
color: #777;
font-size: 0.85em;
padding-bottom: 10px;
}
.em-dia-celula {
position: relative;
padding: 4px;
height: 40px;
display: flex;
flex-direction: column;
align-items: flex-end;
font-size: 0.9em;
border-right: 1px solid #eee;
border-bottom: 1px solid #eee;
}
.em-dia-celula.em-other-month {
background-color: #f9f9f9;
}
.em-dia-celula.today span {
background-color: #e74c3c;
color: #fff;
border-radius: 50%;
width: 28px;
line-height: 26px;
display: inline-block;
text-align: center;
}
.em-event-list {
width: 100%;
margin-top: 5px;
display: flex;
flex-direction: column;
gap: 3px;
overflow: hidden;
}
.em-event {
display: block;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
font-size: 12px;
padding: 2px 6px;
border-radius: 3px;
color: #fff;
background-color: #3498db;
text-decoration: none;
transition: background-color 0.2s;
}
.em-event:hover {
background-color: #217dbb;
}
/* --- Estilos para Tela Cheia --- */
body.em-fullscreen-active {
overflow: hidden;
}
.em-calendario-wrapper.em-fullscreen-mode {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
z-index: 10000;
border-radius: 0;
border: none;
padding: 20px;
box-sizing: border-box;
display: flex;
flex-direction: column;
}
.em-calendario-wrapper.em-fullscreen-mode .em-dias-grid {
flex-grow: 1; /* Faz a grade de dias ocupar o espaço disponível */
}
.em-calendario-wrapper.em-fullscreen-mode .em-dia-celula {
height: auto; /* Altura automática para preencher o espaço */
}
.em-close-fullscreen-btn {
position: absolute;
top: 15px;
right: 20px;
background: none;
border: none;
font-size: 36px;
line-height: 1;
color: #333;
cursor: pointer;
z-index: 10001;
}
.em-close-fullscreen-btn:hover {
color: #e74c3c;
}
/* Estilos para single-evento.php */
.single-evento-container {
max-width: 800px; /* Largura máxima para centralizar */
margin: 0 auto; /* Centraliza horizontalmente */
padding: 30px 20px;
background: #fff;
border-radius: 12px;
box-shadow: 0 4px 20px rgba(44, 62, 80, 0.1);
}
.evento-header {
text-align: center;
margin-bottom: 30px;
}
.evento-header h1 {
font-size: 2rem;
color: #2c3e50;
font-weight: 700;
margin: 0;
line-height: 1.3;
}
.evento-details {
display: flex;
flex-direction: column;
gap: 20px;
}
.evento-info-list {
list-style: none;
padding: 0;
margin: 0;
gap: 12px;
}
.evento-info-list li {
display: flex;
align-items: center;
gap: 10px;
}
.evento-info-list li strong {
min-width: 80px; /* Ajuda a alinhar os rótulos */
}
/* Responsividade */
@media (max-width: 600px) {
.single-evento-container {
padding: 20px 15px;
}
.evento-info-list li {
flex-direction: column;
align-items: flex-start;
gap: 5px;
}
.evento-info-list li strong {
min-width: auto;
}
}

18
assets/js/admin.js Normal file
View File

@@ -0,0 +1,18 @@
jQuery(document).ready(function($) {
$('#data_evento').on('change', function() {
var date = $(this).val();
if (!date) {
alert('Por favor, selecione uma data válida.');
$(this).focus();
}
});
$('#hora_evento').on('change', function() {
var time = $(this).val();
if (time && !/^\d{2}:\d{2}$/.test(time)) {
alert('Por favor, insira uma hora válida no formato HH:MM.');
$(this).val('');
$(this).focus();
}
});
});

View File

@@ -0,0 +1,150 @@
jQuery(document).ready(function($) {
// Itera sobre cada instância de calendário na página
$('.em-calendario-wrapper').each(function() {
const calendarWrapper = $(this);
let currentDate = new Date();
const header = calendarWrapper.find('.em-mes-ano');
const weekDaysContainer = calendarWrapper.find('.em-dias-semana');
const daysGrid = calendarWrapper.find('.em-dias-grid');
// Nomes para internacionalização
const monthNames = ["Janeiro", "Fevereiro", "Março", "Abril", "Maio", "Junho", "Julho", "Agosto", "Setembro", "Outubro", "Novembro", "Dezembro"];
const weekDayNames = ["Dom", "Seg", "Ter", "Qua", "Qui", "Sex", "Sáb"];
function renderCalendar() {
daysGrid.html(''); // Usar .html('') é um pouco mais rápido que .empty()
weekDaysContainer.empty();
const month = currentDate.getMonth();
const year = currentDate.getFullYear();
// Define o cabeçalho (Mês Ano)
header.text(monthNames[month] + ' ' + year);
// Renderiza os dias da semana
weekDayNames.forEach(day => {
weekDaysContainer.append(`<span>${day}</span>`);
});
const firstDayOfMonth = new Date(year, month, 1).getDay();
const daysInMonth = new Date(year, month + 1, 0).getDate();
// Preenche os dias vazios no início do mês
for (let i = 0; i < firstDayOfMonth; i++) {
daysGrid.append('<div class="em-dia-celula em-other-month"></div>');
}
// Renderiza os dias do mês
for (let i = 1; i <= daysInMonth; i++) {
const dayCell = $(`<div class="em-dia-celula" data-date="${year}-${String(month + 1).padStart(2, '0')}-${String(i).padStart(2, '0')}"><span>${i}</span></div>`);
// Marca o dia de hoje
const today = new Date();
if (i === today.getDate() && month === today.getMonth() && year === today.getFullYear()) {
dayCell.addClass('today');
}
daysGrid.append(dayCell);
}
loadEventsForMonth(year, month);
}
function loadEventsForMonth(year, month) {
const startDate = `${year}-${String(month + 1).padStart(2, '0')}-01`;
const endDate = new Date(year, month + 1, 0).toISOString().split('T')[0];
$.ajax({
url: eventosManager.ajaxurl,
type: 'POST',
data: {
action: 'get_eventos_calendario',
security: eventosManager.nonce,
start: startDate,
end: endDate
},
success: function(response) {
if (response.success) {
markEventsOnCalendar(response.data);
}
},
error: function() {
console.error('Erro ao carregar eventos.');
}
});
}
function markEventsOnCalendar(events) {
// 1. Agrupar eventos por data
const eventsByDate = events.reduce((acc, event) => {
const eventDate = event.start.split('T')[0];
if (!acc[eventDate]) {
acc[eventDate] = [];
}
acc[eventDate].push(event);
return acc;
}, {});
// 2. Limpar eventos antigos e renderizar os novos
daysGrid.find('.em-dia-celula').each(function() {
const cell = $(this);
const date = cell.data('date');
// Limpa conteúdo de eventos anteriores
cell.find('.em-event-list').remove();
cell.removeClass('has-event');
if (eventsByDate[date]) {
cell.addClass('has-event');
const eventList = $('<div class="em-event-list"></div>');
eventsByDate[date].forEach(event => {
const eventEl = $(`<a href="${event.url}" class="em-event"></a>`);
eventEl.text(event.title);
eventList.append(eventEl);
});
cell.append(eventList);
}
});
}
// Navegação
calendarWrapper.find('.em-nav-btn').on('click', function() {
const direction = $(this).data('nav');
const currentMonth = currentDate.getMonth();
if (direction === 'prev') {
currentDate.setMonth(currentMonth - 1);
} else if (direction === 'next') {
currentDate.setMonth(currentMonth + 1);
} else if (direction === 'today') {
currentDate = new Date();
}
renderCalendar();
});
// Botão de Tela Cheia
calendarWrapper.find('.em-view-btn[data-view="fullscreen"]').on('click', function() {
calendarWrapper.toggleClass('em-fullscreen-mode');
$('body').toggleClass('em-fullscreen-active');
if (calendarWrapper.hasClass('em-fullscreen-mode')) {
// Adiciona botão de fechar
calendarWrapper.append('<button class="em-close-fullscreen-btn">&times;</button>');
} else {
// Remove botão de fechar
calendarWrapper.find('.em-close-fullscreen-btn').remove();
}
});
// Fechar tela cheia com o botão 'X' (evento delegado)
calendarWrapper.on('click', '.em-close-fullscreen-btn', function() {
calendarWrapper.removeClass('em-fullscreen-mode');
$('body').removeClass('em-fullscreen-active');
$(this).remove();
});
// Renderização inicial
renderCalendar();
});
});

View File

@@ -0,0 +1,41 @@
jQuery(document).ready(function($) {
// Inicializa o calendário se o elemento existir
if ($('#eventos-calendario').length) {
loadEventosCalendario();
}
function loadEventosCalendario() {
$.ajax({
url: eventosManager.ajaxurl,
type: 'POST',
data: {
action: 'get_eventos_calendario',
security: eventosManager.nonce
},
success: function(response) {
if (response.success) {
initFullCalendar(response.data);
}
}
});
}
function initFullCalendar(eventos) {
$('#eventos-calendario').fullCalendar({
header: {
left: 'prev,next today',
center: 'title',
right: 'month,agendaWeek,agendaDay'
},
defaultView: 'month',
editable: false,
events: eventos,
eventColor: '#3498db',
eventTextColor: '#ffffff',
timeFormat: 'H:mm',
eventRender: function(event, element) {
element.find('.fc-title').prepend('<span class="evento-tipo-badge">' + event.tipo + '</span> ');
}
});
}
});

170
eventos-manager.php Normal file
View File

@@ -0,0 +1,170 @@
<?php
/**
* Plugin Name: Gerenciador de Eventos
* Description: Plugin para cadastro e exibição de eventos com calendário.
* Shortcodes disponíveis: [mostra-calendario], [mostra-prox-eventos limit="5" tipo=""], [eventos-completo], [mostra-calendario-widget]
* Version: 1.0
* Author: Marco Antonio Vivas
* Text Domain: gerenciador-eventos
*/
if (!defined('ABSPATH')) {
exit; // Sai se acessado diretamente
}
define('EVENTOS_MANAGER_VERSION', '1.1.0');
define('EVENTOS_MANAGER_PLUGIN_DIR', plugin_dir_path(__FILE__));
define('EVENTOS_MANAGER_PLUGIN_URL', plugin_dir_url(__FILE__));
// Carrega as classes do plugin
require_once EVENTOS_MANAGER_PLUGIN_DIR . 'includes/class-eventos-post-type.php';
require_once EVENTOS_MANAGER_PLUGIN_DIR . 'includes/class-eventos-shortcodes.php';
require_once EVENTOS_MANAGER_PLUGIN_DIR . 'includes/class-eventos-admin.php';
class Eventos_Manager {
public function __construct() {
new Eventos_Post_Type();
new Eventos_Shortcodes();
if (is_admin()) {
new Eventos_Admin();
}
add_action('wp_enqueue_scripts', array($this, 'enqueue_scripts'));
add_action('wp_ajax_get_eventos_calendario', array($this, 'get_eventos_calendario'));
add_action('wp_ajax_nopriv_get_eventos_calendario', array($this, 'get_eventos_calendario'));
add_filter('single_template', array($this, 'load_single_template'));
}
public function enqueue_scripts() {
wp_enqueue_style(
'eventos-manager-css',
EVENTOS_MANAGER_PLUGIN_URL . 'assets/css/eventos-manager.css',
array(),
EVENTOS_MANAGER_VERSION
);
wp_enqueue_script('jquery');
wp_enqueue_script(
'eventos-manager-js',
EVENTOS_MANAGER_PLUGIN_URL . 'assets/js/eventos-manager.js',
array('jquery'),
EVENTOS_MANAGER_VERSION,
true
);
wp_localize_script(
'eventos-manager-js',
'eventosManager',
array(
'ajaxurl' => admin_url('admin-ajax.php'),
'nonce' => wp_create_nonce('eventos_manager_nonce')
)
);
}
public function get_eventos_calendario() {
check_ajax_referer('eventos_manager_nonce', 'security');
$start_date = isset($_POST['start']) ? sanitize_text_field($_POST['start']) : date('Y-m-d', strtotime('-1 month'));
$end_date = isset($_POST['end']) ? sanitize_text_field($_POST['end']) : date('Y-m-d', strtotime('+1 month'));
$args = array(
'post_type' => 'evento',
'posts_per_page' => -1,
'meta_key' => 'data_evento',
'orderby' => 'meta_value',
'order' => 'ASC',
'meta_query' => array(
array(
'key' => 'data_evento',
'value' => array($start_date, $end_date),
'compare' => 'BETWEEN',
'type' => 'DATE'
)
)
);
$eventos = new WP_Query($args);
$calendar_events = array();
if ($eventos->have_posts()) {
while ($eventos->have_posts()) {
$eventos->the_post();
$data_evento = get_post_meta(get_the_ID(), 'data_evento', true);
$hora_evento = get_post_meta(get_the_ID(), 'hora_evento', true);
$tipos = get_the_terms(get_the_ID(), 'tipo_evento');
$tipo = !empty($tipos) && !is_wp_error($tipos) ? $tipos[0]->name : '';
$calendar_events[] = array(
'title' => get_the_title(),
'start' => $data_evento . ($hora_evento ? 'T' . $hora_evento : ''),
'tipo' => $tipo,
'url' => get_permalink()
);
}
wp_reset_postdata();
}
wp_send_json_success($calendar_events);
}
public function load_single_template($template) {
global $post;
if ($post->post_type === 'evento') {
$plugin_template = EVENTOS_MANAGER_PLUGIN_DIR . 'single-evento.php';
if (file_exists($plugin_template)) {
return $plugin_template;
}
}
return $template;
}
}
new Eventos_Manager();
// Register widget
class Eventos_Upcoming_Widget extends WP_Widget {
public function __construct() {
parent::__construct(
'eventos_upcoming_widget',
__('Próximos Eventos', 'eventos-manager'),
array('description' => __('Mostra os próximos eventos', 'eventos-manager'))
);
}
public function widget($args, $instance) {
echo $args['before_widget'];
if (!empty($instance['title'])) {
echo $args['before_title'] . apply_filters('widget_title', $instance['title']) . $args['after_title'];
}
echo do_shortcode('[mostra-prox-eventos limit="' . esc_attr($instance['limit']) . '"]');
echo $args['after_widget'];
}
public function form($instance) {
$title = !empty($instance['title']) ? $instance['title'] : '';
$limit = !empty($instance['limit']) ? $instance['limit'] : 5;
?>
<p>
<label for="<?php echo $this->get_field_id('title'); ?>"><?php _e('Título:'); ?></label>
<input class="widefat" id="<?php echo $this->get_field_id('title'); ?>" name="<?php echo $this->get_field_name('title'); ?>" type="text" value="<?php echo esc_attr($title); ?>">
</p>
<p>
<label for="<?php echo $this->get_field_id('limit'); ?>"><?php _e('Número de eventos:'); ?></label>
<input class="widefat" id="<?php echo $this->get_field_id('limit'); ?>" name="<?php echo $this->get_field_name('limit'); ?>" type="number" value="<?php echo esc_attr($limit); ?>">
</p>
<?php
}
public function update($new_instance, $old_instance) {
$instance = array();
$instance['title'] = (!empty($new_instance['title'])) ? sanitize_text_field($new_instance['title']) : '';
$instance['limit'] = (!empty($new_instance['limit'])) ? intval($new_instance['limit']) : 5;
return $instance;
}
}
add_action('widgets_init', function() {
register_widget('Eventos_Upcoming_Widget');
});

View File

@@ -0,0 +1,116 @@
<?php
class Eventos_Admin {
public function __construct() {
add_action('add_meta_boxes', array($this, 'add_meta_boxes'));
add_action('save_post', array($this, 'save_evento_meta'));
add_action('admin_enqueue_scripts', array($this, 'enqueue_admin_scripts'));
add_action('admin_menu', array($this, 'add_help_page'));
}
public function add_meta_boxes() {
add_meta_box(
'evento_metabox',
__('Detalhes do Evento', 'eventos-manager'),
array($this, 'render_evento_metabox'),
'evento',
'normal',
'high'
);
}
public function render_evento_metabox($post) {
wp_nonce_field('evento_meta_nonce', 'evento_meta_nonce');
$data_evento = get_post_meta($post->ID, 'data_evento', true);
$hora_evento = get_post_meta($post->ID, 'hora_evento', true);
$local_evento = get_post_meta($post->ID, 'local_evento', true);
?>
<div class="evento-metabox">
<div class="meta-field">
<label for="data_evento"><?php _e('Data do Evento', 'eventos-manager'); ?></label>
<input type="date" id="data_evento" name="data_evento" value="<?php echo esc_attr($data_evento); ?>" required>
</div>
<div class="meta-field">
<label for="hora_evento"><?php _e('Hora do Evento', 'eventos-manager'); ?></label>
<input type="time" id="hora_evento" name="hora_evento" value="<?php echo esc_attr($hora_evento); ?>">
</div>
<div class="meta-field">
<label for="local_evento"><?php _e('Local do Evento', 'eventos-manager'); ?></label>
<input type="text" id="local_evento" name="local_evento" value="<?php echo esc_attr($local_evento); ?>">
</div>
</div>
<?php
}
public function save_evento_meta($post_id) {
if (!isset($_POST['evento_meta_nonce']) || !wp_verify_nonce($_POST['evento_meta_nonce'], 'evento_meta_nonce')) {
return;
}
if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
return;
}
if (!current_user_can('edit_post', $post_id)) {
return;
}
if (isset($_POST['data_evento']) && preg_match('/^\d{4}-\d{2}-\d{2}$/', $_POST['data_evento'])) {
update_post_meta($post_id, 'data_evento', sanitize_text_field($_POST['data_evento']));
}
if (isset($_POST['hora_evento']) && preg_match('/^\d{2}:\d{2}$/', $_POST['hora_evento'])) {
update_post_meta($post_id, 'hora_evento', sanitize_text_field($_POST['hora_evento']));
}
if (isset($_POST['local_evento'])) {
update_post_meta($post_id, 'local_evento', sanitize_text_field($_POST['local_evento']));
}
}
public function enqueue_admin_scripts() {
global $post_type;
if ('evento' == $post_type) {
wp_enqueue_style(
'eventos-manager-admin-css',
EVENTOS_MANAGER_PLUGIN_URL . 'assets/css/admin.css',
array(),
EVENTOS_MANAGER_VERSION
);
wp_enqueue_script(
'eventos-manager-admin-js',
EVENTOS_MANAGER_PLUGIN_URL . 'assets/js/admin.js',
array('jquery'),
EVENTOS_MANAGER_VERSION,
true
);
}
}
public function add_help_page() {
add_submenu_page(
'edit.php?post_type=evento',
__('Ajuda - Gerenciador de Eventos', 'eventos-manager'),
__('Ajuda', 'eventos-manager'),
'manage_options',
'eventos-manager-help',
array($this, 'render_help_page')
);
}
public function render_help_page() {
?>
<div class="wrap">
<h1><?php _e('Ajuda - Gerenciador de Eventos', 'eventos-manager'); ?></h1>
<p><?php _e('Este plugin permite gerenciar eventos com um calendário e shortcodes.', 'eventos-manager'); ?></p>
<h2><?php _e('Shortcodes Disponíveis', 'eventos-manager'); ?></h2>
<ul>
<li><code>[mostra-calendario]</code>: <?php _e('Exibe o calendário de eventos.', 'eventos-manager'); ?></li>
<li><code>[mostra-prox-eventos limit="5" tipo=""]</code>: <?php _e('Exibe uma lista de próximos eventos. Atributos: limit (número de eventos), tipo (slug do tipo de evento).', 'eventos-manager'); ?></li>
<li><code>[eventos-completo]</code>: <?php _e('Exibe o calendário e a lista de próximos eventos juntos.', 'eventos-manager'); ?></li>
</ul>
</div>
<?php
}
}

View File

@@ -0,0 +1,61 @@
<?php
class Eventos_Post_Type {
public function __construct() {
add_action('init', array($this, 'register_post_type'));
add_action('init', array($this, 'register_taxonomy'));
}
public function register_post_type() {
$labels = array(
'name' => __('Eventos', 'eventos-manager'),
'singular_name' => __('Evento', 'eventos-manager'),
'menu_name' => __('Eventos', 'eventos-manager'),
'add_new' => __('Adicionar Novo', 'eventos-manager'),
'add_new_item' => __('Adicionar Novo Evento', 'eventos-manager'),
'edit_item' => __('Editar Evento', 'eventos-manager'),
'new_item' => __('Novo Evento', 'eventos-manager'),
'view_item' => __('Ver Evento', 'eventos-manager'),
'search_items' => __('Buscar Eventos', 'eventos-manager'),
'not_found' => __('Nenhum evento encontrado', 'eventos-manager'),
'not_found_in_trash' => __('Nenhum evento encontrado na lixeira', 'eventos-manager')
);
$args = array(
'labels' => $labels,
'public' => true,
'has_archive' => true,
'menu_icon' => 'dashicons-calendar-alt',
'supports' => array('title', 'editor', 'thumbnail'),
'rewrite' => array('slug' => 'eventos'),
'show_in_rest' => true
);
register_post_type('evento', $args);
}
public function register_taxonomy() {
$labels = array(
'name' => __('Tipos de Evento', 'eventos-manager'),
'singular_name' => __('Tipo de Evento', 'eventos-manager'),
'search_items' => __('Buscar Tipos', 'eventos-manager'),
'all_items' => __('Todos os Tipos', 'eventos-manager'),
'edit_item' => __('Editar Tipo', 'eventos-manager'),
'update_item' => __('Atualizar Tipo', 'eventos-manager'),
'add_new_item' => __('Adicionar Novo Tipo', 'eventos-manager'),
'new_item_name' => __('Novo Nome de Tipo', 'eventos-manager'),
'menu_name' => __('Tipos de Evento', 'eventos-manager')
);
$args = array(
'hierarchical' => true,
'labels' => $labels,
'show_ui' => true,
'show_admin_column' => true,
'query_var' => true,
'rewrite' => array('slug' => 'tipo-evento'),
'show_in_rest' => true
);
register_taxonomy('tipo_evento', 'evento', $args);
}
}

View File

@@ -0,0 +1,135 @@
<?php
class Eventos_Shortcodes {
public function __construct() {
add_shortcode('mostra-calendario', array($this, 'render_calendario'));
add_shortcode('mostra-prox-eventos', array($this, 'render_proximos_eventos'));
add_shortcode('eventos-completo', array($this, 'render_eventos_completo'));
add_shortcode('mostra-calendario-widget', array($this, 'render_calendario_widget')); // NOVO SHORTCODE
}
public function render_calendario($atts) {
ob_start();
?>
<div id="eventos-calendario" class="em-calendario-wrapper" data-view="full">
<div class="em-calendario-header em-toolbar">
<div class="em-toolbar-section">
<button class="em-nav-btn" data-nav="prev">&lt;</button>
<button class="em-nav-btn" data-nav="next">&gt;</button>
<button class="em-nav-btn em-today-btn" data-nav="today">Hoje</button>
</div>
<div class="em-toolbar-section em-toolbar-center"><h3 class="em-mes-ano"></h3></div>
<div class="em-toolbar-section em-toolbar-right">
<button class="em-view-btn" data-view="fullscreen" title="Tela Cheia">⛶</button>
</div>
</div>
<div class="em-dias-semana"></div>
<div class="em-dias-grid"></div>
</div>
<?php
return ob_get_clean();
}
public function render_proximos_eventos($atts) {
$atts = shortcode_atts(array(
'limit' => 5,
'tipo' => ''
), $atts, 'mostra-prox-eventos');
$args = array(
'post_type' => 'evento',
'posts_per_page' => intval($atts['limit']),
'meta_key' => 'data_evento',
'orderby' => 'meta_value',
'order' => 'ASC',
'meta_query' => array(
array(
'key' => 'data_evento',
'value' => date('Y-m-d'),
'compare' => '>=',
'type' => 'DATE'
)
)
);
if (!empty($atts['tipo'])) {
$args['tax_query'] = array(
array(
'taxonomy' => 'tipo_evento',
'field' => 'slug',
'terms' => sanitize_text_field($atts['tipo'])
)
);
}
$eventos = new WP_Query($args);
ob_start();
?>
<div class="proximos-eventos-box">
<h4>Próximos Eventos</h4>
<ul class="proximos-eventos-lista">
<?php if ($eventos->have_posts()) : ?>
<?php while ($eventos->have_posts()) : $eventos->the_post(); ?>
<?php
$data_evento = get_post_meta(get_the_ID(), 'data_evento', true);
$hora_evento = get_post_meta(get_the_ID(), 'hora_evento', true);
$tipos = get_the_terms(get_the_ID(), 'tipo_evento');
?>
<li>
<div class="evento-data">
<?php echo date_i18n('d M', strtotime($data_evento)); ?>
</div>
<div>
<div class="evento-titulo"><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></div>
<?php if ($hora_evento) : ?>
<div class="evento-hora"><?php echo $hora_evento; ?></div>
<?php endif; ?>
</div>
<?php if ($tipos && !is_wp_error($tipos)) : ?>
<span class="evento-tipo"><?php echo $tipos[0]->name; ?></span>
<?php endif; ?>
</li>
<?php endwhile; wp_reset_postdata(); ?>
<?php else : ?>
<li>Nenhum evento agendado</li>
<?php endif; ?>
</ul>
</div>
<?php
return ob_get_clean();
}
public function render_eventos_completo($atts) {
ob_start();
?>
<div class="noticias-eventos-wrapper">
<div class="noticias-col">
<?php echo $this->render_calendario($atts); ?>
</div>
<div class="eventos-col">
<?php echo $this->render_proximos_eventos($atts); ?>
</div>
</div>
<?php
return ob_get_clean();
}
public function render_calendario_widget($atts) {
ob_start();
?>
<div id="eventos-calendario-widget" class="em-calendario-wrapper" data-view="widget">
<div class="em-calendario-header em-toolbar">
<div class="em-toolbar-section">
<button class="em-nav-btn" data-nav="prev">&lt;</button>
<button class="em-nav-btn" data-nav="next">&gt;</button>
</div>
<div class="em-toolbar-section em-toolbar-center"><h3 class="em-mes-ano"></h3></div>
<div class="em-toolbar-section"></div>
</div>
<div class="em-dias-semana"></div>
<div class="em-dias-grid"></div>
</div>
<?php
return ob_get_clean();
}
}

31
single-evento.php Normal file
View File

@@ -0,0 +1,31 @@
<?php
get_header();
if (have_posts()) : while (have_posts()) : the_post();
$data_evento = get_post_meta(get_the_ID(), 'data_evento', true);
$hora_evento = get_post_meta(get_the_ID(), 'hora_evento', true);
$local_evento = get_post_meta(get_the_ID(), 'local_evento', true);
$tipos = get_the_terms(get_the_ID(), 'tipo_evento');
?>
</br><article class="single-evento-container">
<header class="evento-header">
<h1><?php the_title(); ?></h1>
</header>
<div class="evento-details">
<ul class="evento-info-list">
<li><strong>Data:</strong> <?php echo date_i18n('d/m/Y', strtotime($data_evento)); ?></li>
<?php if ($hora_evento) : ?>
<li><strong>Hora:</strong> <?php echo esc_html($hora_evento); ?></li>
<?php endif; ?>
<?php if ($local_evento) : ?>
<li><strong>Local:</strong> <?php echo esc_html($local_evento); ?></li>
<?php endif; ?>
<?php if ($tipos && !is_wp_error($tipos)) : ?>
<li><strong>Tipo:</strong> <span class="evento-tipo"><?php echo esc_html($tipos[0]->name); ?></span></li>
<?php endif; ?>
</ul>
<div class="evento-content"><?php the_content(); ?></div>
</div>
</article>
<?php
endwhile; endif;
get_footer();