本文續接 WordPress 外掛開發 – 讀取CSV檔匯入使用者資訊
原本是提到透過CSV匯入客戶註冊後,需提供分群功能,以便日後針對不同客群寄送邀請信。因此已經開始想像我們可能需要新增一張Table customer_group,裡面有幾個關鍵欄位,例如群組ID、群組名稱、以 json 資料格式儲存所有使用者ID
以當時情境,並不需要以一對多來新增 群組ID 與 使用者ID 的關聯表
要發送邀請函時,則透過選擇群組來寄送,完全把功能往複雜了想。
作者同時間必須開發與維護許多功能,許多系統功能更是一次性使用便可能因為成效不佳而夭折,因此除非已經看到未來定會擴充,不然通常會保留許多彈性,但就是這些動作導致,額外花了很多不必要的時間。
然而,在經過多次會議討論,發現所謂的群組並沒有再利用性,也就是說建立群組完全是不需要的事情,因此調整後做法變成,使用者只要拿著那份從 CRM 匯出的 CSV 檔(這個檔案裡面就包含著這次參與的成員)依序操作:
- 上傳CSV匯入使用者
- 上傳CSV做一些批次更新的操作
- 上傳CSV寄信
有沒有覺得對要操作的管理人員來說省事很多,也由於我們用了 JS 解讀 CSV 檔案,在用戶端就能解決也不用上傳到Server,只需要透過這份名單,配合 Ajax 就能進行各項操作
相關程式碼附於下方
<?php
// 我們在使用者選單內建立一個子選單
add_action('admin_menu', function() {
add_submenu_page(
'users', // 父選單 slug
'寄邀請信', // 頁面標題
'寄邀請信', // 選單標題
'manage_options', // 權限
'send-invitation-emails', // 子選單 slug
'render_send_invitation_page' // 回呼函數
);
});
function render_send_invitation_page() {
?>
<div class="wrap">
<h1>寄邀請信</h1>
<!-- 收件者 CSV 上傳 -->
<label for="recipients-csv">收件者:</label>
<input type="file" id="recipients-csv" accept=".csv">
<table id="recipients-table">
<thead>
<tr>
<th><input type="checkbox" id="select-all" /> 全選</th>
<th>Email</th>
<th>First Name</th>
<th>Last Name</th>
<th>操作結果</th>
</tr>
</thead>
<tbody>
<!-- 這裡將根據 CSV 載入動態產生行 -->
</tbody>
</table>
<!-- 發送按鈕 -->
<button id="send-invites">發送邀請信</button>
<script>
document.getElementById('recipients-csv').addEventListener('change', function(event) {
const file = event.target.files[0];
if (file) {
const reader = new FileReader();
reader.onload = function(e) {
const rows = e.target.result.split("\n");
const table = document.getElementById("recipients-table");
const tbody = table.querySelector("tbody"); // 取得 tbody 來清空資料行
tbody.innerHTML = ''; // 清空 tbody 內的資料行
const rowsData = rows.slice(1); // 跳過 CSV 第一筆資料(標題)
rowsData.forEach((row, index) => {
// 檢查每一行是否是空的,去除前後空白並確保有內容才處理
const trimmedRow = row.trim();
if (trimmedRow === "") return; // 如果是空行則跳過
const cols = trimmedRow.split(",");
if (cols.length > 0) {
const tr = document.createElement("tr");
// 添加選擇框(第一列)
const checkboxTd = document.createElement("td");
const checkbox = document.createElement("input");
checkbox.type = "checkbox";
checkbox.classList.add("recipient-checkbox");
checkbox.setAttribute("data-row-index", index); // 標記行索引
checkboxTd.appendChild(checkbox);
tr.appendChild(checkboxTd);
// 只取需要的欄位 (第 2, 6, 7 欄) email, first name, last_name
const selectedCols = [cols[1], cols[5], cols[6]];
// 其他欄位
selectedCols.forEach((col, colIndex) => {
const td = document.createElement("td");
td.textContent = col.trim();
tr.appendChild(td);
});
// 將表格列加入表格
tbody.appendChild(tr);
}
});
};
reader.readAsText(file);
}
// 全選/全取消功能
document.getElementById("select-all").addEventListener("change", function(e) {
const checkboxes = document.querySelectorAll(".recipient-checkbox");
checkboxes.forEach(checkbox => {
checkbox.checked = e.target.checked;
});
});
// 按下發送按鈕時只發送選中的收件人
document.getElementById("send-invitation-btn").addEventListener("click", function() {
const selectedEmails = [];
const checkboxes = document.querySelectorAll(".recipient-checkbox:checked");
checkboxes.forEach(checkbox => {
const row = checkbox.closest("tr");
const email = row.cells[1].textContent.trim(); // 假設第二欄是 email
selectedEmails.push({
email: email,
tr: row // 存儲 tr 元素以便後續更新
});
});
// 呼叫後端發送邀請信的函數,傳遞選中的 emails
sendEmails(selectedEmails);
});
function sendEmails(emails) {
emails.forEach(email => {
// 在發送前清空結果欄位
const resultTd = tr.querySelector("td:last-child"); // 取得該行最後一個 td
resultTd.textContent = "處理中...";
resultTd.style.color = "#ff9800"; // 橙色,表示處理中
$.post(ajaxurl, {
action: 'send_invitation_email',
recipient_email: email,
// 其他必要參數
}, function(response) {
// 顯示每封信發送的結果
console.log(response);
});
});
}
});
document.getElementById('send-invites').addEventListener('click', function() {
const rows = document.querySelectorAll("#recipients-table tr");
rows.forEach(row => {
const recipient = row.cells[0].textContent;
const data = {
action: 'send_invitation_email',
recipient_email: recipient
};
jQuery.post(ajaxurl, data, function(response) {
console.log("發送給 " + recipient + ":" + response.data);
// 更新成功可以回寫剛剛的 table 操作結果欄位
});
});
});
</script>
</div>
<?php
}
add_action('wp_ajax_send_invitation_email', function() {
$template_id = 1; // 以某篇 post 當作範本內容
$sender_name = '寄件人名稱';
$sender_email = 'no-reply@yourdomain';
$recipient_email = sanitize_email($_POST['recipient_email']);
// 取得信件範本內容
$template = get_post($template_id);
$subject = get_the_title($template);
$message = apply_filters('the_content', $template->post_content);
// 使用 WordPress wp_mail 發送郵件
$headers = ['From: ' . $sender_name . ' <' . $sender_email . '>'];
$result = wp_mail($recipient_email, $subject, $message, $headers);
if ($result) {
wp_send_json_success("成功發送");
} else {
wp_send_json_error("發送失敗");
}
});