Canned Responses - replies an agent puts into a ticket in one go, * from the picker above the reply box. Each is offered on tickets in the * ticket categories it is set to, or on every ticket, and its placeholders * are filled in from the ticket as it goes in. Each row shows what it says, * where it is offered, what picking it sets up on the reply (who sees it, * the status after it, time worked), the files that go with it and how often * it has gone into a reply. A response can be changed, copied as the start of * another, exported, archived - not offered on tickets - or deleted. The New * button's menu imports and exports them as a file, and leads to the * Canned Responses report and the starter ones. * * Active and Archived hold the shared ones; Agents' own the ones agents made * for themselves (in their account, or saved from a reply), each with whose * it is - one can be shared with everyone from its menu. The work is in * functions/canned_response.php; the handlers are admin/post/canned_response.php. */ // Default Column Sortby Filter $sort = "canned_response_name"; $order = "ASC"; require_once "includes/inc_all_admin.php"; // The views: the shared ones offered now, the agents' own, and the archived ones $views = [ '' => ['label' => 'Active', 'icon' => 'fa-comment-dots', 'where' => 'canned_response_archived_at IS NULL AND canned_response_user_id = 0', 'title' => 'Shared - offered to everyone'], 'personal' => ['label' => "Agents' own", 'icon' => 'fa-user', 'where' => 'canned_response_archived_at IS NULL AND canned_response_user_id > 0', 'title' => 'Offered to the agent who made each - share one with everyone from its menu'], 'archived' => ['label' => 'Archived', 'icon' => 'fa-archive', 'where' => 'canned_response_archived_at IS NOT NULL', 'title' => 'Not offered on tickets'], ]; $show = (string) ($_GET['show'] ?? ''); $show = isset($views[$show]) ? $show : ''; $show_archived = $show === 'archived'; // Where it is offered: any, every ticket (no category), or one ticket category $category_filter = (string) ($_GET['category'] ?? ''); $category_filter = $category_filter === 'every' || intval($category_filter) > 0 ? ($category_filter === 'every' ? 'every' : (string) intval($category_filter)) : ''; // Only these sort - an unknown column would take the page down $sortable_columns = [ 'canned_response_name' => "canned_response_name $order", 'use_count' => "use_count $order, canned_response_name ASC", 'last_used' => "last_used IS NULL, last_used $order, canned_response_name ASC", ]; if (!isset($sortable_columns[$sort])) { $sort = 'canned_response_name'; } $filters = "(canned_response_name LIKE '%$q%' OR canned_response_body LIKE '%$q%')"; if ($category_filter === 'every') { $filters .= " AND NOT EXISTS (SELECT 1 FROM canned_response_categories c WHERE c.canned_response_id = canned_responses.canned_response_id)"; } elseif ($category_filter !== '') { $filters .= " AND EXISTS (SELECT 1 FROM canned_response_categories c WHERE c.canned_response_id = canned_responses.canned_response_id AND c.category_id = " . intval($category_filter) . ")"; } $sql = mysqli_query($mysqli, "SELECT SQL_CALC_FOUND_ROWS canned_responses.canned_response_id, canned_response_name, canned_response_body, canned_response_reply_type, canned_response_ticket_status, canned_response_minutes, canned_response_user_id, canned_response_created_at, canned_response_updated_at, canned_response_archived_at, owner.user_name AS owner_name, COALESCE(used.use_count, 0) AS use_count, used.last_used FROM canned_responses LEFT JOIN users owner ON owner.user_id = canned_response_user_id AND canned_response_user_id > 0 LEFT JOIN ( SELECT canned_response_use_canned_response_id AS used_id, COUNT(*) AS use_count, MAX(canned_response_use_created_at) AS last_used FROM canned_response_uses GROUP BY canned_response_use_canned_response_id ) used ON used.used_id = canned_responses.canned_response_id WHERE $filters AND {$views[$show]['where']} ORDER BY {$sortable_columns[$sort]}, canned_responses.canned_response_id ASC LIMIT $record_from, $record_to"); $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()")); $responses = []; while ($row = mysqli_fetch_assoc($sql)) { $responses[intval($row['canned_response_id'])] = $row; } $response_categories = cannedResponseCategoriesFor(array_keys($responses)); $response_files = cannedResponseFilesFor(array_keys($responses)); $counts = mysqli_fetch_row(mysqli_query($mysqli, "SELECT " . implode(', ', array_map(function ($view) { return "COALESCE(SUM({$view['where']}), 0)"; }, $views)) . " FROM canned_responses WHERE $filters")); $view_counts = array_combine(array_keys($views), $counts); $sort_link = function ($column, $label) use ($url_query_strings_sort, $sort, $disp, $order_icon) { return '' . $label . ($sort === $column ? " $order_icon" : '') . ''; }; $pill_url = function ($view) use ($category_filter) { return '?' . http_build_query(array_filter(['q' => $_GET['q'] ?? '', 'category' => $category_filter, 'show' => $view])); }; $add_url = 'modals/canned_response/canned_response_add.php' . (intval($category_filter) > 0 ? '?category=' . intval($category_filter) : ''); $csrf = $_SESSION['csrf_token']; ?>

Canned Responses

"> $row) { $name = escapeHtml($row['canned_response_name']); $edit_url = "modals/canned_response/canned_response_edit.php?id=$canned_response_id"; $use_count = intval($row['use_count']); $used_text = $use_count ? $use_count . ' time' . ($use_count === 1 ? '' : 's') : ''; $categories = $response_categories[$canned_response_id] ?? []; $offered_html = $categories ? '' . implode('', array_map(function ($category) { return '' . categoryChip($category) . ''; }, $categories)) . '' : 'Every ticket'; $preview = cannedResponsePreview($row['canned_response_body']); $sets_up = cannedResponseSetsUpHtml($row); $files = $response_files[$canned_response_id] ?? []; $owner_id = intval($row['canned_response_user_id']); ?>
Offered on
file
Archived
Not yet' ?> >
'canned responses', 'icon' => 'fa-comment-dots', 'filtered' => $q !== '' || $category_filter !== '', 'archived' => $show_archived, 'views' => ['show'], 'view' => $show === 'personal' ? [ 'title' => "No agents' own canned responses", 'icon' => 'fa-user', 'text' => 'Agents make their own in their account, under Canned Responses, or with Save as canned response on a ticket reply. Share one with everyone from its menu here.', 'actions' => [], ] : [], 'text' => 'Replies agents put into a ticket in one go - "Password reset done", "Waiting on you". [Contact], [Ticket], [Agent] and the like are filled in from the ticket.', 'actions' => [['label' => 'New Canned Response', 'modal' => $add_url, 'size' => 'lg']], ]; require_once "../includes/filter_footer.php"; ?>