Initial commit
This commit is contained in:
185
includes/admin-ui.php
Normal file
185
includes/admin-ui.php
Normal file
@@ -0,0 +1,185 @@
|
||||
<?php
|
||||
// Adicionar meta boxes para tickets
|
||||
function sts_add_ticket_meta_boxes() {
|
||||
add_meta_box(
|
||||
'sts_ticket_details',
|
||||
__('Detalhes do Ticket', 'simple-ticket-system'),
|
||||
'sts_ticket_details_callback',
|
||||
'ticket',
|
||||
'side',
|
||||
'high'
|
||||
);
|
||||
|
||||
add_meta_box(
|
||||
'sts_ticket_responses',
|
||||
__('Respostas', 'simple-ticket-system'),
|
||||
'sts_ticket_responses_callback',
|
||||
'ticket',
|
||||
'normal',
|
||||
'high'
|
||||
);
|
||||
}
|
||||
add_action('add_meta_boxes', 'sts_add_ticket_meta_boxes');
|
||||
|
||||
// Callback para detalhes do ticket
|
||||
function sts_ticket_details_callback($post) {
|
||||
wp_nonce_field('sts_save_ticket_data', 'sts_ticket_nonce');
|
||||
|
||||
$status = wp_get_object_terms($post->ID, 'ticket_status', array('fields' => 'names'));
|
||||
$current_status = !empty($status) ? $status[0] : 'Aberto';
|
||||
|
||||
$type = wp_get_object_terms($post->ID, 'ticket_type', array('fields' => 'names'));
|
||||
$current_type = !empty($type) ? $type[0] : __('Nenhum', 'simple-ticket-system');
|
||||
|
||||
$author_id = $post->post_author;
|
||||
$author = get_userdata($author_id);
|
||||
$attachments = get_attached_media('', $post->ID);
|
||||
$ticket_id = get_post_meta($post->ID, '_sts_ticket_id', true);
|
||||
|
||||
echo '<p><strong>' . __('ID do Ticket:', 'simple-ticket-system') . '</strong> ' . esc_html($ticket_id) . '</p>';
|
||||
|
||||
echo '<p><strong>' . __('Criado por:', 'simple-ticket-system') . '</strong> ' . $author->display_name . '</p>';
|
||||
echo '<p><strong>' . __('Email:', 'simple-ticket-system') . '</strong> ' . $author->user_email . '</p>';
|
||||
echo '<p><strong>' . __('Data:', 'simple-ticket-system') . '</strong> ' . get_the_date('d/m/Y H:i', $post->ID) . '</p>';
|
||||
|
||||
echo '<label for="ticket_status"><strong>' . __('Status:', 'simple-ticket-system') . '</strong></label>';
|
||||
echo '<select name="ticket_status" id="ticket_status" style="width:100%">';
|
||||
|
||||
$statuses = get_terms(array(
|
||||
'taxonomy' => 'ticket_status',
|
||||
'hide_empty' => false
|
||||
));
|
||||
|
||||
foreach ($statuses as $status) {
|
||||
echo '<option value="' . $status->name . '" ' . selected($current_status, $status->name, false) . '>' . $status->name . '</option>';
|
||||
}
|
||||
|
||||
echo '</select>';
|
||||
|
||||
echo '<p style="margin-top:10px;"><strong>' . __('Tipo de Solicitação:', 'simple-ticket-system') . '</strong> ' . esc_html($current_type) . '</p>';
|
||||
|
||||
if (!empty($attachments)) {
|
||||
echo '<p style="margin-top:10px;"><strong>' . __('Anexos:', 'simple-ticket-system') . '</strong></p>';
|
||||
echo '<ul>';
|
||||
foreach ($attachments as $attachment) {
|
||||
echo '<li><a href="' . wp_get_attachment_url($attachment->ID) . '" target="_blank">' . esc_html($attachment->post_title) . '</a></li>';
|
||||
}
|
||||
echo '</ul>';
|
||||
} else {
|
||||
echo '<p style="margin-top:10px;"><strong>' . __('Anexos:', 'simple-ticket-system') . '</strong> ' . __('Nenhum anexo.', 'simple-ticket-system') . '</p>';
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Callback para respostas do ticket
|
||||
function sts_ticket_responses_callback($post) {
|
||||
$responses = get_comments(array(
|
||||
'post_id' => $post->ID,
|
||||
'order' => 'ASC'
|
||||
));
|
||||
|
||||
echo '<div class="sts-responses">';
|
||||
|
||||
if ($responses) {
|
||||
foreach ($responses as $response) {
|
||||
echo '<div class="sts-response">';
|
||||
echo '<p><strong>' . $response->comment_author . '</strong> <em>' . date('d/m/Y H:i', strtotime($response->comment_date)) . '</em></p>';
|
||||
echo '<div>' . wpautop($response->comment_content) . '</div>';
|
||||
echo '</div><hr>';
|
||||
}
|
||||
} else {
|
||||
echo '<p>' . __('Nenhuma resposta ainda.', 'simple-ticket-system') . '</p>';
|
||||
}
|
||||
|
||||
echo '</div>';
|
||||
|
||||
// Formulário para nova resposta
|
||||
echo '<h3>' . __('Adicionar Resposta', 'simple-ticket-system') . '</h3>';
|
||||
echo '<textarea name="sts_response_content" style="width:100%; height:100px;"></textarea>';
|
||||
echo '<p class="description">' . __('Digite sua resposta acima e atualize o ticket.', 'simple-ticket-system') . '</p>';
|
||||
}
|
||||
|
||||
// Salvar dados do ticket
|
||||
function sts_save_ticket_data($post_id) {
|
||||
if (!isset($_POST['sts_ticket_nonce']) || !wp_verify_nonce($_POST['sts_ticket_nonce'], 'sts_save_ticket_data')) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!current_user_can('edit_post', $post_id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Salvar status
|
||||
if (isset($_POST['ticket_status'])) {
|
||||
$status_name = sanitize_text_field($_POST['ticket_status']);
|
||||
$term = get_term_by('name', $status_name, 'ticket_status');
|
||||
if ($term && !is_wp_error($term)) {
|
||||
wp_set_object_terms($post_id, $term->term_id, 'ticket_status');
|
||||
} else {
|
||||
wp_set_object_terms($post_id, $status_name, 'ticket_status');
|
||||
}
|
||||
}
|
||||
|
||||
// Salvar resposta se houver
|
||||
if (!empty($_POST['sts_response_content'])) {
|
||||
$user = wp_get_current_user();
|
||||
|
||||
$comment_data = array(
|
||||
'comment_post_ID' => $post_id,
|
||||
'comment_author' => $user->display_name,
|
||||
'comment_author_email' => $user->user_email,
|
||||
'comment_content' => wp_kses_post($_POST['sts_response_content']),
|
||||
'comment_type' => '',
|
||||
'comment_parent' => 0,
|
||||
'user_id' => $user->ID,
|
||||
'comment_approved' => 1,
|
||||
);
|
||||
|
||||
$comment_id = wp_insert_comment($comment_data);
|
||||
|
||||
if ($comment_id) {
|
||||
// Enviar notificação por email
|
||||
sts_notify_ticket_response($post_id, $comment_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
add_action('save_post_ticket', 'sts_save_ticket_data', 10, 1);
|
||||
|
||||
// Personalizar colunas na lista de tickets
|
||||
function sts_custom_ticket_columns($columns) {
|
||||
$new_columns = array(
|
||||
'cb' => $columns['cb'],
|
||||
'ticket_id' => __('ID', 'simple-ticket-system'),
|
||||
'title' => $columns['title'],
|
||||
'author' => __('Autor', 'simple-ticket-system'),
|
||||
'ticket_type' => __('Tipo', 'simple-ticket-system'),
|
||||
'status' => __('Status', 'simple-ticket-system'),
|
||||
'date' => $columns['date']
|
||||
);
|
||||
|
||||
return $new_columns;
|
||||
}
|
||||
add_filter('manage_ticket_posts_columns', 'sts_custom_ticket_columns');
|
||||
|
||||
function sts_custom_ticket_column_data($column, $post_id) {
|
||||
switch ($column) {
|
||||
case 'status':
|
||||
$status = wp_get_object_terms($post_id, 'ticket_status', array('fields' => 'names'));
|
||||
if (!empty($status)) {
|
||||
$status_class = sanitize_title($status[0]);
|
||||
echo '<span class="sts-admin-status status-' . esc_attr($status_class) . '">' . esc_html($status[0]) . '</span>';
|
||||
} else {
|
||||
echo __('Nenhum status definido', 'simple-ticket-system');
|
||||
}
|
||||
break;
|
||||
case 'ticket_id':
|
||||
$ticket_id = get_post_meta($post_id, '_sts_ticket_id', true);
|
||||
echo $ticket_id ? '<strong>' . esc_html($ticket_id) . '</strong>' : '';
|
||||
break;
|
||||
}
|
||||
}
|
||||
add_action('manage_ticket_posts_custom_column', 'sts_custom_ticket_column_data', 10, 2);
|
25
includes/assets.php
Normal file
25
includes/assets.php
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
// Evitar acesso direto
|
||||
if (!defined('ABSPATH')) {
|
||||
exit;
|
||||
}
|
||||
|
||||
function sts_enqueue_frontend_assets() {
|
||||
// Enfileira o CSS do frontend
|
||||
wp_enqueue_style('sts-frontend-style', STS_URL . 'assets/css/frontend.css', array(), STS_VERSION);
|
||||
|
||||
// Enfileira o JS do frontend
|
||||
wp_enqueue_script('sts-frontend-script', STS_URL . 'assets/js/frontend.js', array(), STS_VERSION, true);
|
||||
}
|
||||
add_action('wp_enqueue_scripts', 'sts_enqueue_frontend_assets');
|
||||
|
||||
function sts_enqueue_admin_assets($hook) {
|
||||
$screen = get_current_screen();
|
||||
|
||||
// Carrega o CSS apenas nas páginas de listagem e edição do post type 'ticket'
|
||||
if (isset($screen->post_type) && $screen->post_type == 'ticket') {
|
||||
wp_enqueue_style('sts-admin-style', STS_URL . 'assets/css/admin.css', array(), STS_VERSION);
|
||||
}
|
||||
}
|
||||
add_action('admin_enqueue_scripts', 'sts_enqueue_admin_assets');
|
99
includes/frontend.php
Normal file
99
includes/frontend.php
Normal file
@@ -0,0 +1,99 @@
|
||||
<?php
|
||||
// Shortcode para formulário de abertura de ticket
|
||||
function sts_ticket_form_shortcode() {
|
||||
ob_start();
|
||||
|
||||
if (is_user_logged_in()) {
|
||||
include STS_PATH . 'templates/form-ticket.php';
|
||||
} else {
|
||||
echo '<p>' . __('Você precisa estar logado para abrir um ticket.', 'simple-ticket-system') . '</p>';
|
||||
echo wp_login_form(array('echo' => false));
|
||||
}
|
||||
|
||||
return ob_get_clean();
|
||||
}
|
||||
add_shortcode('ticket_form', 'sts_ticket_form_shortcode');
|
||||
|
||||
// Shortcode para visualização de tickets do usuário
|
||||
function sts_my_tickets_shortcode() {
|
||||
ob_start();
|
||||
|
||||
if (is_user_logged_in()) {
|
||||
include STS_PATH . 'templates/view-ticket.php';
|
||||
} else {
|
||||
echo '<p>' . __('Você precisa estar logado para visualizar seus tickets.', 'simple-ticket-system') . '</p>';
|
||||
echo wp_login_form(array('echo' => false));
|
||||
}
|
||||
|
||||
return ob_get_clean();
|
||||
}
|
||||
add_shortcode('my_tickets', 'sts_my_tickets_shortcode');
|
||||
|
||||
// Processar envio do formulário de ticket
|
||||
function sts_process_ticket_form() {
|
||||
if (isset($_POST['sts_submit_ticket']) && wp_verify_nonce($_POST['sts_ticket_form_nonce'], 'sts_ticket_form')) {
|
||||
$current_user = wp_get_current_user();
|
||||
$title = sanitize_text_field($_POST['sts_ticket_title']);
|
||||
$content = wp_kses_post($_POST['sts_ticket_content']);
|
||||
$type_id = isset($_POST['sts_ticket_type']) ? (int) $_POST['sts_ticket_type'] : 0;
|
||||
|
||||
$post_data = array(
|
||||
'post_title' => $title,
|
||||
'post_content' => $content,
|
||||
'post_status' => 'publish',
|
||||
'post_type' => 'ticket',
|
||||
'post_author' => $current_user->ID
|
||||
);
|
||||
|
||||
$post_id = wp_insert_post($post_data);
|
||||
|
||||
if (!is_wp_error($post_id)) {
|
||||
// Gerar e salvar o ID personalizado
|
||||
$last_id = get_option('sts_last_ticket_id', 0);
|
||||
$new_id = $last_id + 1;
|
||||
$ticket_id_formatted = 'DTI-' . sprintf('%03d', $new_id);
|
||||
|
||||
update_post_meta($post_id, '_sts_ticket_id', $ticket_id_formatted);
|
||||
update_option('sts_last_ticket_id', $new_id);
|
||||
|
||||
// Definir status padrão
|
||||
wp_set_object_terms($post_id, 'Aberto', 'ticket_status');
|
||||
|
||||
// Definir tipo de solicitação
|
||||
if ($type_id > 0) {
|
||||
wp_set_object_terms($post_id, $type_id, 'ticket_type');
|
||||
}
|
||||
|
||||
// Lidar com o anexo
|
||||
if (!empty($_FILES['sts_ticket_attachment']['name'])) {
|
||||
require_once(ABSPATH . 'wp-admin/includes/file.php');
|
||||
require_once(ABSPATH . 'wp-admin/includes/media.php');
|
||||
require_once(ABSPATH . 'wp-admin/includes/image.php');
|
||||
|
||||
$attachment_id = media_handle_upload('sts_ticket_attachment', $post_id);
|
||||
}
|
||||
|
||||
// Enviar notificação
|
||||
sts_notify_new_ticket($post_id);
|
||||
|
||||
// Redireciona para a página do shortcode, não para o permalink do novo post.
|
||||
wp_redirect(add_query_arg('ticket_submitted', 'success', wp_get_referer()));
|
||||
exit;
|
||||
} else {
|
||||
wp_redirect(add_query_arg('ticket_submitted', 'error', wp_get_referer()));
|
||||
exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
add_action('init', 'sts_process_ticket_form');
|
||||
|
||||
// Carregar o template para a página de um único ticket
|
||||
function sts_single_ticket_template($single_template) {
|
||||
global $post;
|
||||
|
||||
if ($post->post_type == 'ticket') {
|
||||
$single_template = STS_PATH . 'templates/single-ticket.php';
|
||||
}
|
||||
return $single_template;
|
||||
}
|
||||
add_filter('single_template', 'sts_single_ticket_template');
|
51
includes/notifications.php
Normal file
51
includes/notifications.php
Normal file
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
// Notificar sobre novo ticket
|
||||
function sts_notify_new_ticket($post_id) {
|
||||
$post = get_post($post_id);
|
||||
$author = get_userdata($post->post_author);
|
||||
$admin_email = get_option('admin_email');
|
||||
|
||||
$subject = __('Novo Ticket Criado', 'simple-ticket-system') . ': ' . $post->post_title;
|
||||
|
||||
$message = __("Um novo ticket foi criado no sistema.\n\n", 'simple-ticket-system');
|
||||
$message .= __('Título: ', 'simple-ticket-system') . $post->post_title . "\n";
|
||||
$message .= __('Autor: ', 'simple-ticket-system') . $author->display_name . "\n";
|
||||
$message .= __('Email: ', 'simple-ticket-system') . $author->user_email . "\n";
|
||||
$message .= __('Conteúdo: ', 'simple-ticket-system') . "\n" . $post->post_content . "\n\n";
|
||||
$message .= __('Para visualizar e responder ao ticket, acesse: ', 'simple-ticket-system') . admin_url('post.php?post=' . $post_id . '&action=edit') . "\n";
|
||||
|
||||
wp_mail($admin_email, $subject, $message);
|
||||
}
|
||||
|
||||
// Notificar sobre resposta ao ticket
|
||||
function sts_notify_ticket_response($post_id, $comment_id) {
|
||||
$post = get_post($post_id);
|
||||
$comment = get_comment($comment_id);
|
||||
$author = get_userdata($post->post_author);
|
||||
|
||||
// Notificar o autor do ticket
|
||||
$subject = __('Nova Resposta no Seu Ticket', 'simple-ticket-system') . ': ' . $post->post_title;
|
||||
|
||||
$message = __("Seu ticket recebeu uma nova resposta.\n\n", 'simple-ticket-system');
|
||||
$message .= __('Ticket: ', 'simple-ticket-system') . $post->post_title . "\n";
|
||||
$message .= __('Resposta de: ', 'simple-ticket-system') . $comment->comment_author . "\n";
|
||||
$message .= __('Resposta: ', 'simple-ticket-system') . "\n" . $comment->comment_content . "\n\n";
|
||||
$message .= __('Para visualizar o ticket completo, acesse: ', 'simple-ticket-system') . get_permalink($post_id) . "\n";
|
||||
|
||||
wp_mail($author->user_email, $subject, $message);
|
||||
|
||||
// Se a resposta não foi do admin, notificar o admin
|
||||
if (!user_can($comment->user_id, 'manage_options')) {
|
||||
$admin_email = get_option('admin_email');
|
||||
$subject = __('Nova Resposta no Ticket', 'simple-ticket-system') . ': ' . $post->post_title;
|
||||
|
||||
$message = __("Um ticket recebeu uma nova resposta.\n\n", 'simple-ticket-system');
|
||||
$message .= __('Ticket: ', 'simple-ticket-system') . $post->post_title . "\n";
|
||||
$message .= __('Autor do Ticket: ', 'simple-ticket-system') . $author->display_name . "\n";
|
||||
$message .= __('Resposta de: ', 'simple-ticket-system') . $comment->comment_author . "\n";
|
||||
$message .= __('Resposta: ', 'simple-ticket-system') . "\n" . $comment->comment_content . "\n\n";
|
||||
$message .= __('Para visualizar e responder ao ticket, acesse: ', 'simple-ticket-system') . admin_url('post.php?post=' . $post_id . '&action=edit') . "\n";
|
||||
|
||||
wp_mail($admin_email, $subject, $message);
|
||||
}
|
||||
}
|
107
includes/post-types.php
Normal file
107
includes/post-types.php
Normal file
@@ -0,0 +1,107 @@
|
||||
<?php
|
||||
// Registrar Custom Post Type para tickets
|
||||
function sts_register_ticket_post_type() {
|
||||
$labels = array(
|
||||
'name' => __('Tickets', 'simple-ticket-system'),
|
||||
'singular_name' => __('Ticket', 'simple-ticket-system'),
|
||||
'menu_name' => __('Tickets', 'simple-ticket-system'),
|
||||
'name_admin_bar' => __('Ticket', 'simple-ticket-system'),
|
||||
'add_new' => __('Novo Ticket', 'simple-ticket-system'),
|
||||
'add_new_item' => __('Adicionar Novo Ticket', 'simple-ticket-system'),
|
||||
'new_item' => __('Novo Ticket', 'simple-ticket-system'),
|
||||
'edit_item' => __('Editar Ticket', 'simple-ticket-system'),
|
||||
'view_item' => __('Ver Ticket', 'simple-ticket-system'),
|
||||
'all_items' => __('Todos os Tickets', 'simple-ticket-system'),
|
||||
'search_items' => __('Procurar Tickets', 'simple-ticket-system'),
|
||||
'not_found' => __('Nenhum ticket encontrado.', 'simple-ticket-system'),
|
||||
'not_found_in_trash' => __('Nenhum ticket na lixeira.', 'simple-ticket-system')
|
||||
);
|
||||
|
||||
$args = array(
|
||||
'labels' => $labels,
|
||||
'public' => true,
|
||||
'has_archive' => false,
|
||||
'publicly_queryable' => true,
|
||||
'show_ui' => true,
|
||||
'show_in_menu' => true,
|
||||
'query_var' => true,
|
||||
'rewrite' => array('slug' => 'ticket'),
|
||||
'capability_type' => 'post',
|
||||
'capabilities' => array(
|
||||
'create_posts' => false, // Remover capacidade de criar diretamente
|
||||
),
|
||||
'map_meta_cap' => true,
|
||||
'hierarchical' => false,
|
||||
'menu_position' => null,
|
||||
'supports' => array('title', 'editor', 'author'),
|
||||
'menu_icon' => 'dashicons-tickets'
|
||||
);
|
||||
|
||||
register_post_type('ticket', $args);
|
||||
|
||||
// Registrar taxonomia para status
|
||||
$status_labels = array(
|
||||
'name' => __('Status', 'simple-ticket-system'),
|
||||
'singular_name' => __('Status', 'simple-ticket-system'),
|
||||
'search_items' => __('Procurar Status', 'simple-ticket-system'),
|
||||
'all_items' => __('Todos os Status', 'simple-ticket-system'),
|
||||
'edit_item' => __('Editar Status', 'simple-ticket-system'),
|
||||
'update_item' => __('Atualizar Status', 'simple-ticket-system'),
|
||||
'add_new_item' => __('Adicionar Novo Status', 'simple-ticket-system'),
|
||||
'new_item_name' => __('Novo Nome de Status', 'simple-ticket-system'),
|
||||
'menu_name' => __('Status', 'simple-ticket-system'),
|
||||
);
|
||||
|
||||
$status_args = array(
|
||||
'hierarchical' => true,
|
||||
'labels' => $status_labels,
|
||||
'show_ui' => true,
|
||||
'show_admin_column' => true,
|
||||
'query_var' => true,
|
||||
'rewrite' => array('slug' => 'ticket-status'),
|
||||
);
|
||||
|
||||
register_taxonomy('ticket_status', 'ticket', $status_args);
|
||||
|
||||
// Registrar taxonomia para Tipo de Solicitação
|
||||
$type_labels = array(
|
||||
'name' => __('Tipos de Solicitação', 'simple-ticket-system'),
|
||||
'singular_name' => __('Tipo de Solicitação', 'simple-ticket-system'),
|
||||
'search_items' => __('Procurar Tipos', 'simple-ticket-system'),
|
||||
'all_items' => __('Todos os Tipos', 'simple-ticket-system'),
|
||||
'edit_item' => __('Editar Tipo', 'simple-ticket-system'),
|
||||
'update_item' => __('Atualizar Tipo', 'simple-ticket-system'),
|
||||
'add_new_item' => __('Adicionar Novo Tipo', 'simple-ticket-system'),
|
||||
'new_item_name' => __('Novo Nome de Tipo', 'simple-ticket-system'),
|
||||
'menu_name' => __('Tipos de Solicitação', 'simple-ticket-system'),
|
||||
);
|
||||
|
||||
$type_args = array(
|
||||
'hierarchical' => true,
|
||||
'labels' => $type_labels,
|
||||
'show_ui' => true,
|
||||
'show_admin_column' => true,
|
||||
'query_var' => true,
|
||||
'rewrite' => array('slug' => 'ticket-type'),
|
||||
);
|
||||
|
||||
register_taxonomy('ticket_type', 'ticket', $type_args);
|
||||
|
||||
// Adicionar status padrão
|
||||
$default_statuses = array('Aberto', 'Em Andamento', 'Resolvido');
|
||||
|
||||
foreach ($default_statuses as $status) {
|
||||
if (!term_exists($status, 'ticket_status')) {
|
||||
wp_insert_term($status, 'ticket_status');
|
||||
}
|
||||
}
|
||||
|
||||
// Adicionar tipos padrão
|
||||
$default_types = array('Dúvida', 'Problema Técnico', 'Sugestão');
|
||||
foreach ($default_types as $type) {
|
||||
if (!term_exists($type, 'ticket_type')) {
|
||||
wp_insert_term($type, 'ticket_type');
|
||||
}
|
||||
}
|
||||
}
|
||||
add_action('init', 'sts_register_ticket_post_type');
|
Reference in New Issue
Block a user