Phần 1: Hướng Dẫn Tạo Chức Năng Gửi Link Tải Về Qua Email Trong WordPress
Trong bài viết này, chúng ta sẽ xây dựng một chức năng cho phép người dùng tải về một file hoặc tài liệu sau khi nhấn vào nút “Tải về”. Link tải sẽ được gửi trực tiếp đến email của người dùng, giúp bảo vệ tài nguyên và tăng tương tác với người dùng.

1. Tại Sao Nên Dùng Chức Năng Gửi Link Qua Email?
- Bảo vệ tài nguyên: Hạn chế người dùng không mong muốn tải file mà không để lại thông tin.
- Tăng tương tác: Khuyến khích người dùng đăng ký hoặc đăng nhập để nhận tài nguyên.
- Quản lý lượt tải: Giúp bạn theo dõi ai đã tải file và có thể gửi thông tin cập nhật sau này.
2. Cách Thêm Chức Năng Vào WordPress
2.1. Tạo Meta Box Cho Link Tải Xuống
Trước tiên, chúng ta cần tạo một meta box để nhập link tải xuống trong phần quản trị bài viết.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | function add_download_link_meta_box() { add_meta_box( 'download_link', 'Link Tải Về', 'render_download_link_meta_box', 'post', 'normal', 'high' ); } add_action('add_meta_boxes', 'add_download_link_meta_box'); function render_download_link_meta_box($post) { wp_nonce_field('save_download_link_meta_box', 'download_link_nonce'); $download_link = get_post_meta($post->ID, '_download_link', true); echo '<input type="url" name="download_link" value="' . esc_attr($download_link) . '" style="width:100%;" />'; } |
2.2. Lưu Link Tải Xuống Khi Lưu Bài Viết
1 2 3 4 5 6 7 8 9 10 11 12 | function save_download_link_meta_box($post_id) { if (!isset($_POST['download_link_nonce']) || !wp_verify_nonce($_POST['download_link_nonce'], 'save_download_link_meta_box')) { return; } if (!current_user_can('edit_post', $post_id)) { return; } if (isset($_POST['download_link'])) { update_post_meta($post_id, '_download_link', esc_url_raw($_POST['download_link'])); } } add_action('save_post', 'save_download_link_meta_box'); |
2.3. Hiển Thị Nút Tải Về Trong Bài Viết
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | function add_download_button($content) { if (is_single() && is_main_query()) { $download_link = get_post_meta(get_the_ID(), '_download_link', true); if ($download_link) { ob_start(); ?> <button id="download-button" class="nut-tai-ve" style="background-color: #0073aa; color: white; padding: 10px;"> Tải về </button> <script> document.getElementById('download-button').addEventListener('click', function () { fetch('<?php echo admin_url('admin-ajax.php'); ?>?action=send_download_link&post_id=<?php echo get_the_ID(); ?>') .then(response => response.json()) .then(data => alert(data.message)); }); </script> <?php $content .= ob_get_clean(); } } return $content; } add_filter('the_content', 'add_download_button'); |
2.4. Một số cải tiến khác cho chức năng tải về
Để cải tiến chức năng của bạn, có thể thêm một số tính năng và cải thiện giao diện người dùng, chẳng hạn như:
Hiển thị thông báo khi chưa nhập link tải về: Bạn có thể kiểm tra xem link tải về có được nhập hay không và thông báo cho người dùng nếu chưa nhập.
Thêm kiểm tra hợp lệ cho link tải về: Đảm bảo rằng link tải về được nhập đúng định dạng và hợp lệ (ví dụ: URL hợp lệ).
Cải thiện giao diện cho nút tải về: Có thể thêm hiệu ứng hoạt hình hoặc cải thiện giao diện của nút tải xuống để người dùng cảm thấy thân thiện hơn khi sử dụng.
Kiểm tra xem người dùng có nhập email không (nếu chưa đăng nhập): Trong trường hợp người dùng chưa đăng nhập, bạn có thể yêu cầu họ nhập email để gửi link.
Sau đây là ví dụ code được cải tiến với những tính năng trên, nếu muốn dùng các cải tiến dưới đây vui lòng tìm các funtion tương ứng ở code trên để thay thành funtion code dưới cho đúng nhé:
1. Kiểm tra link tải về và hiển thị thông báo nếu chưa nhập
Trong hàm render_download_link_meta_box
, bạn có thể thêm kiểm tra điều kiện nếu link tải về trống và hiển thị thông báo.
1 2 3 4 5 6 7 8 9 10 | function render_download_link_meta_box($post) { $download_link = get_post_meta($post->ID, '_download_link', true); ?> <label for="download_link">Link tải về:</label> <input type="text" id="download_link" name="download_link" value="<?php echo esc_attr($download_link); ?>" style="width:100%;" /> <?php if (empty($download_link)) { echo '<p style="color:red;">Vui lòng nhập link tải về.</p>'; } } |
2. Kiểm tra hợp lệ cho link tải về
Để đảm bảo rằng link tải về là hợp lệ, bạn có thể thêm kiểm tra định dạng URL trong hàm save_download_link_meta_box
:
1 2 3 4 5 6 7 8 9 10 11 12 13 | function save_download_link_meta_box($post_id) { if (array_key_exists('download_link', $_POST)) { $download_link = $_POST['download_link']; // Kiểm tra link tải về có hợp lệ không if (!filter_var($download_link, FILTER_VALIDATE_URL)) { // Nếu link không hợp lệ, không lưu và hiển thị thông báo lỗi wp_die('Link tải về không hợp lệ. Vui lòng kiểm tra lại.'); } update_post_meta($post_id, '_download_link', $download_link); } } |
3. Cải thiện giao diện cho nút tải về
Để cải thiện giao diện của nút tải về, bạn có thể sử dụng thêm CSS để làm nút đẹp hơn. Dưới đây là ví dụ với nút có hiệu ứng hover và cải thiện kiểu dáng:
1 2 3 4 5 6 7 8 9 | <button id="download-button" class="nut-tai-ve" style="margin-top: 20px; padding: 10px 20px; background-color: #0073aa; color: white; border: none; cursor: pointer; border-radius: 5px; transition: background-color 0.3s;"> <?php echo is_user_logged_in() ? 'Tải về' : 'Hãy đăng nhập để tải về'; ?> </button> <style> .nut-tai-ve:hover { background-color: #005177; } </style> |
4. Yêu cầu nhập email nếu chưa đăng nhập
Nếu người dùng chưa đăng nhập, thay vì hiển thị thông báo yêu cầu đăng nhập, bạn có thể yêu cầu họ nhập email để gửi link tải về.
Ví dụ, thay vì dùng Swal.fire
chỉ thông báo cần đăng nhập, bạn có thể thay thế bằng một form nhập email:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 | <script type="text/javascript"> document.getElementById('download-button').addEventListener('click', function () { <?php if (is_user_logged_in()) : ?> let countdown = Math.floor(Math.random() * (200 - 90 + 1)) + 90; // Random từ 90 đến 200 giây let interval; let isCountingDown = false; function startCountdown() { isCountingDown = true; Swal.fire({ title: '<i class="fas fa-hourglass-start"></i> Vui lòng chờ ' + countdown + ' giây', html: ` <div style="margin-top: 10px;"> <i class="fas fa-spinner fa-spin fa-3x"></i> <p style="margin-top: 10px;">Sẽ gửi link đến email sau <b><span id="timer">` + countdown + `</span></b> giây.</p> </div> `, allowOutsideClick: false, allowEscapeKey: false, showConfirmButton: false, timerProgressBar: true, didOpen: () => { const timer = Swal.getHtmlContainer().querySelector('#timer'); interval = setInterval(() => { countdown--; timer.textContent = countdown; if (countdown <= 0) { clearInterval(interval); isCountingDown = false; sendDownloadLink(); } }, 1000); }, willClose: () => { clearInterval(interval); isCountingDown = false; } }); } function sendDownloadLink() { fetch('<?php echo admin_url('admin-ajax.php'); ?>?action=send_download_link&post_id=<?php echo get_the_ID(); ?>') .then(response => response.json()) .then(data => { if (data.success) { Swal.fire({ icon: 'success', title: '<i class="fas fa-check-circle"></i> Link tải về đã được gửi!', html: '<p>Link tải về đã được gửi đến email của bạn.</p>', allowOutsideClick: true, allowEscapeKey: true, showConfirmButton: true, confirmButtonText: 'Đóng', confirmButtonColor: '#0073aa' }); } else { Swal.fire({ icon: 'error', title: '<i class="fas fa-exclamation-triangle"></i> Lỗi!', html: '<p>Đã có lỗi xảy ra khi gửi email hoặc email đã được gửi trong 30 ngày qua.</p>', allowOutsideClick: true, allowEscapeKey: true, showConfirmButton: true, confirmButtonText: 'Thử lại', confirmButtonColor: '#d33' }); } }); } startCountdown(); <?php else : ?> Swal.fire({ title: 'Vui lòng nhập email của bạn', input: 'email', inputLabel: 'Email của bạn', inputPlaceholder: 'Nhập email của bạn', showCancelButton: true, confirmButtonText: 'Gửi', cancelButtonText: 'Hủy', preConfirm: (email) => { if (!email) { Swal.showValidationMessage('Vui lòng nhập email'); } else { // Gửi email cho người dùng return fetch('<?php echo admin_url('admin-ajax.php'); ?>?action=send_download_link&email=' + email) .then(response => response.json()) .then(data => { if (data.success) { Swal.fire({ icon: 'success', title: 'Link tải về đã được gửi!', html: 'Link tải về đã được gửi đến email của bạn.', }); } }); } } }); <?php endif; ?> }); </script> |
Bằng cách này, nếu người dùng chưa đăng nhập, họ sẽ được yêu cầu nhập email của mình để nhận link tải về.
Hy vọng những cải tiến này sẽ giúp chức năng của bạn hoàn thiện hơn!
3. Kết luận
Bằng cách áp dụng các đoạn mã trên, bạn có thể dễ dàng tạo một hệ thống gửi link tải về qua email trong WordPress. Điều này không chỉ giúp bảo vệ nội dung mà còn mang lại trải nghiệm chuyên nghiệp hơn cho người dùng.
Bạn có thể tùy chỉnh thêm để phù hợp với nhu cầu của mình! Hãy tải file code hoàn chỉnh bằng cách nhấp vào nút tải về ở phía dưới nhé. MUATHEMEWPGIARE cảm ơn các bạn đã đọc bài, có vấn đề gì hãy để lại bình luận để bên mình hỗ trợ nhé.
Phần 2: Cập nhật Chức Năng Tải Về Qua Trong WordPress Khi Điểm Danh Đủ Số
Dưới đây là phiên bản hoàn chỉnh của mã code với tất cả các chức năng và thông báo bằng SweetAlert2, bao gồm phần điểm danh và tải về, cũng như các thông báo cần thiết. Toàn bộ các tính năng đã được tích hợp và hoàn thiện như yêu cầu.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 | // Thêm trường nhập link tải xuống và số ngày điểm danh trong phần tạo bài viết function add_download_link_meta_box() { add_meta_box( 'download_link', // ID của meta box 'Link Tải Về & Điểm Danh', // Tiêu đề của meta box 'render_download_link_meta_box', // Hàm callback để hiển thị meta box 'post', // Hiển thị trên loại bài viết nào (post) 'normal', 'high' ); } add_action('add_meta_boxes', 'add_download_link_meta_box'); function render_download_link_meta_box($post) { $download_link = get_post_meta($post->ID, '_download_link', true); $attendance_days_required = get_post_meta($post->ID, '_attendance_days_required', true); ?> <label for="download_link">Link tải về:</label> <input type="text" id="download_link" name="download_link" value="<?php echo esc_attr($download_link); ?>" style="width:100%;" /> <label for="attendance_days_required" style="margin-top: 10px;">Số ngày điểm danh yêu cầu:</label> <input type="number" id="attendance_days_required" name="attendance_days_required" value="<?php echo esc_attr($attendance_days_required); ?>" style="width:100%;" /> <?php } // Lưu link tải về và số ngày điểm danh khi bài viết được lưu function save_download_link_meta_box($post_id) { if (array_key_exists('download_link', $_POST)) { update_post_meta($post_id, '_download_link', $_POST['download_link']); } if (array_key_exists('attendance_days_required', $_POST)) { update_post_meta($post_id, '_attendance_days_required', $_POST['attendance_days_required']); } } add_action('save_post', 'save_download_link_meta_box'); // Thêm nút tải về và kiểm tra điểm danh vào cuối bài viết // Thêm nút tải về và điểm danh vào cuối bài viết function add_download_button($content) { if (is_single() && is_main_query()) { $post_id = get_the_ID(); $download_link = get_post_meta($post_id, '_download_link', true); $attendance_days_required = get_post_meta($post_id, '_attendance_days', true); // Lấy số ngày điểm danh đã hoàn thành của người dùng đối với bài viết này $user_id = get_current_user_id(); $attendance_days_completed = (int) get_user_meta($user_id, '_attendance_days_completed_' . $post_id, true); $last_attendance_date = get_user_meta($user_id, '_last_attendance_date_' . $post_id, true); $current_date = date('Y-m-d'); // Kiểm tra xem người dùng đã điểm danh trong ngày chưa $can_attend_today = ($last_attendance_date !== $current_date); // Kiểm tra nếu người dùng đã đăng nhập if ($user_id === 0) { // Người dùng chưa đăng nhập, hiển thị nút yêu cầu đăng nhập $content .= '<div class="attendance-message" style="margin-top: 20px; padding: 10px; background-color: #f0ad4e; color: white;"> <p>Hãy đăng nhập để điểm danh bài viết này.</p> <button id="login-button" class="login-button" style="margin-top: 20px; padding: 10px 20px; background-color: #0073aa; color: white; border: none; cursor: pointer;"> Đăng nhập để điểm danh </button> </div>'; // Thêm mã JavaScript để hiển thị SweetAlert khi người dùng nhấn "Đăng nhập" $content .= '<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script> <script> document.getElementById("login-button").addEventListener("click", function() { Swal.fire({ icon: "info", title: "Bạn cần đăng nhập!", text: "Vui lòng đăng nhập để thực hiện điểm danh.", showCancelButton: true, confirmButtonText: "Đăng nhập", cancelButtonText: "Hủy" }).then((result) => { if (result.isConfirmed) { window.location.href = "' . wp_login_url() . '"; // Chuyển hướng người dùng đến trang đăng nhập } }); }); </script>'; } else { // Nếu người dùng đã đăng nhập if ($download_link) { ob_start(); // Nếu người dùng đã hoàn thành đủ số ngày điểm danh if ($attendance_days_completed >= $attendance_days_required) { ?> <div class="attendance-message" style="margin-top: 20px; padding: 10px; background-color: #28a745; color: white;"> <p>Bạn đã điểm danh đủ <?php echo $attendance_days_required; ?> ngày. Bạn có thể tải về bài viết này!</p> <button id="download-button" class="nut-tai-ve" style="margin-top: 20px; padding: 10px 20px; background-color: #0073aa; color: white; border: none; cursor: pointer;"> Tải về </button> <script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script> <script> document.getElementById('download-button').addEventListener('click', function () { let countdown = Math.floor(Math.random() * (3 - 2 + 1)) + 3; let interval; let isCountingDown = false; function startCountdown() { isCountingDown = true; Swal.fire({ title: 'Vui lòng chờ...', html: '<div style="margin-top: 10px;">' + '<i class="fas fa-spinner fa-spin fa-3x"></i>' + '<p style="margin-top: 10px;">Sẽ chuyển đến link tải về sau <b><span id="timer">' + countdown + '</span></b> giây.</p>' + '</div>', allowOutsideClick: false, allowEscapeKey: false, showConfirmButton: false, timerProgressBar: true, didOpen: () => { const timer = Swal.getHtmlContainer().querySelector('#timer'); interval = setInterval(() => { countdown--; timer.textContent = countdown; if (countdown <= 0) { clearInterval(interval); window.location.href = '<?php echo esc_url($download_link); ?>'; // Chuyển hướng đến link tải về } }, 1000); } }); } startCountdown(); }); </script> </div> <?php } else { // Nếu người dùng chưa đủ số ngày điểm danh $days_left = $attendance_days_required - $attendance_days_completed; ?> <div class="attendance-message" style="margin-top: 20px; padding: 10px; background-color: #f0ad4e; color: white;"> <p>Bạn đã điểm danh <?php echo $attendance_days_completed; ?> ngày, còn <?php echo $days_left; ?> ngày nữa để tải về.</p> </div> <?php if ($can_attend_today) { ?> <button id="attendance-button" class="attendance-button" style="margin-top: 20px; padding: 10px 20px; background-color: #28a745; color: white; border: none; cursor: pointer;"> Điểm danh hôm nay </button> <script> document.getElementById('attendance-button').addEventListener('click', function () { fetch('<?php echo admin_url('admin-ajax.php'); ?>?action=update_attendance&post_id=<?php echo $post_id; ?>') .then(response => response.json()) .then(data => { if (data.success) { Swal.fire({ icon: 'success', title: 'Điểm danh thành công!', text: 'Bạn đã điểm danh hôm nay cho bài viết này.', confirmButtonText: 'Đóng', }).then(() => { document.querySelector('.attendance-message').innerHTML = '<p>Điểm danh thành công! Bạn đã hoàn thành ' + (<?php echo $attendance_days_completed; ?> + 1) + ' ngày.</p>'; document.getElementById('attendance-button').disabled = true; }); } else { Swal.fire({ icon: 'error', title: 'Lỗi!', text: data.message, }); } }); }); </script> <?php } else { ?> <div class="attendance-message" style="margin-top: 20px; padding: 10px; background-color: #5bc0de; color: white;"> <p>Bạn đã điểm danh hôm nay rồi. Vui lòng quay lại vào ngày mai để tiếp tục điểm danh.</p> </div> <?php } } $content .= ob_get_clean(); } } } return $content; } add_filter('the_content', 'add_download_button'); // Xử lý Ajax để gửi email function send_download_link() { // Kiểm tra xem người dùng đã đăng nhập chưa if (is_user_logged_in() && isset($_GET['post_id'])) { $post_id = intval($_GET['post_id']); $download_link = get_post_meta($post_id, '_download_link', true); $current_user = wp_get_current_user(); // Kiểm tra số ngày điểm danh $attendance_days_completed = (int) get_user_meta($current_user->ID, '_attendance_days_completed_' . $post_id, true); $attendance_days_required = get_post_meta($post_id, '_attendance_days_required', true); // Nếu người dùng chưa hoàn thành đủ số ngày điểm danh if ($attendance_days_completed < $attendance_days_required) { wp_send_json_error(['message' => 'Bạn cần điểm danh ít nhất ' . $attendance_days_required . ' ngày để tải về.']); return; } if ($download_link) { $user_email = $current_user->user_email; $post_title = get_the_title($post_id); $last_sent_key = '_last_email_sent_' . $current_user->ID . '_' . $post_id; // Kiểm tra thời gian lần gửi email trước $last_sent_time = get_user_meta($current_user->ID, $last_sent_key, true); $current_time = current_time('timestamp'); // Nếu đã gửi trong 30 ngày qua, từ chối yêu cầu if ($last_sent_time && ($current_time - $last_sent_time) < 30 * DAY_IN_SECONDS) { wp_send_json_error(['message' => 'Link đã được gửi trong 30 ngày qua.']); return; } // Tiến hành gửi email $subject = 'Link tải về cho bài viết: ' . $post_title; $message = 'Xin chào ' . $current_user->display_name . ",\n\n"; $message .= 'Bạn đã yêu cầu tải về từ bài viết "' . $post_title . '". Đây là link tải về của bạn: ' . $download_link . "\n\n"; $message .= 'Trân trọng,\nWebsite của bạn'; if (wp_mail($user_email, $subject, $message)) { // Cập nhật thời gian gửi email cho người dùng update_user_meta($current_user->ID, $last_sent_key, $current_time); wp_send_json_success(); } else { wp_send_json_error(['message' => 'Có lỗi xảy ra khi gửi email. Vui lòng thử lại sau.']); } } else { wp_send_json_error(['message' => 'Link tải về không tồn tại.']); } } else { wp_send_json_error(['message' => 'Bạn cần đăng nhập để yêu cầu link tải về.']); } } add_action('wp_ajax_send_download_link', 'send_download_link'); // Cập nhật số ngày điểm danh cho người dùng khi họ điểm danh function update_attendance() { if (is_user_logged_in() && isset($_GET['post_id'])) { $post_id = intval($_GET['post_id']); $user_id = get_current_user_id(); // Lấy thông tin số ngày điểm danh của người dùng $attendance_days_completed = (int) get_user_meta($user_id, '_attendance_days_completed_' . $post_id, true); // Kiểm tra nếu người dùng chưa điểm danh hôm nay $last_attendance_date = get_user_meta($user_id, '_last_attendance_date_' . $post_id, true); $today = date('Y-m-d'); if ($last_attendance_date === $today) { wp_send_json_error(['message' => 'Bạn đã điểm danh hôm nay rồi.']); return; } // Cập nhật số ngày điểm danh $attendance_days_completed++; update_user_meta($user_id, '_attendance_days_completed_' . $post_id, $attendance_days_completed); update_user_meta($user_id, '_last_attendance_date_' . $post_id, $today); wp_send_json_success(['message' => 'Điểm danh thành công!']); } else { wp_send_json_error(['message' => 'Bạn cần đăng nhập để điểm danh.']); } } add_action('wp_ajax_update_attendance', 'update_attendance'); |
Các Thông báo SweetAlert2
Điểm danh thành công: Khi người dùng điểm danh thành công, thông báo
Điểm danh thành công!
sẽ xuất hiện.Chưa đủ số ngày điểm danh: Khi người dùng chưa đủ số ngày điểm danh yêu cầu, sẽ hiển thị thông báo yêu cầu đủ ngày điểm danh.
Thông báo lỗi gửi email: Nếu có lỗi khi gửi email hoặc email đã được gửi trong 30 ngày qua, sẽ xuất hiện thông báo lỗi.
Thông báo đăng nhập yêu cầu: Khi người dùng chưa đăng nhập và cố gắng tải về, thông báo yêu cầu đăng nhập sẽ hiện lên.
Tên File | Thông tin | Hành động |
---|---|---|
Download |
☕ Mời mình một ly cà phê nhỏ?
Nếu bạn thấy nội dung hữu ích, hãy ủng hộ một ly cà phê để mình có thêm động lực phát triển nhé!
LE TRUNG HOANG - 0766734539


📣 Tham gia nhóm Zalo hỗ trợ
Nhận trợ giúp, cập nhật kiến thức và chia sẻ tài nguyên miễn phí cùng cộng đồng:
👉 Tham gia nhóm Zalo- Hướng dẫn chi tiết cách thêm nút Like và Share Facebook cho website WordPress
- Hướng dẫn và chia sẻ code thêm nút xóa và tăng giảm số lượng sản phẩm trong trang thanh toán WooCommerce cho Flatsome
- Sharecode Maxton – Mẫu Bảng Điều Khiển Quản Trị Bootstrap 5 Đa Năng và Chuyên Nghiệp
- SEO là gì? Tổng hợp tất cả kiến thức về Search Engine Optimize
- Thêm trường số điện thoại, xoá trường email, website và chống spam bình luận bài viết