Bạn đang muốn thêm tính năng điểm danh hàng ngày để tăng tương tác người dùng trên website WordPress? Bài viết này sẽ hướng dẫn bạn cách làm.
Phần 1: Tích Hợp Hệ Thống Điểm Danh Hằng Ngày Cho WordPress
Để triển khai hệ thống điểm danh trong WordPress, trước tiên bạn cần đăng ký các scripts và styles như SweetAlert2 để hiển thị thông báo đẹp mắt, đồng thời sử dụng wp_localize_script() để truyền dữ liệu AJAX từ PHP sang JavaScript. Tiếp theo, tạo các bảng trong database để lưu lịch sử điểm danh, điểm người dùng, mã giảm giá và cài đặt hệ thống bằng dbDelta() trong hàm init_daily_checkin_system(). Tính năng này giúp tăng tương tác người dùng, thưởng điểm, và quy đổi mã giảm giá một cách linh hoạt.

|
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 |
// Đăng ký scripts và styles function register_daily_checkin_assets() { // Đăng ký SweetAlert2 wp_register_script('sweetalert2', 'https://cdn.jsdelivr.net/npm/sweetalert2@11', array(), '11.0.0', true); wp_register_style('sweetalert2', 'https://cdn.jsdelivr.net/npm/sweetalert2@11/dist/sweetalert2.min.css', array(), '11.0.0'); // // Đăng ký script và style chính cho hệ thống điểm danh // wp_register_script('daily-checkin', get_template_directory_uri() . '/assets/js/daily-checkin.js', array('jquery', 'sweetalert2'), '1.0.0', true); // wp_register_style('daily-checkin', get_template_directory_uri() . '/assets/css/daily-checkin.css', array(), '1.0.0'); // Localize script để truyền AJAX URL và nonce wp_localize_script('daily-checkin', 'daily_checkin_obj', array( 'ajax_url' => admin_url('admin-ajax.php'), 'nonce' => wp_create_nonce('daily_checkin_nonce'), 'is_logged_in' => is_user_logged_in(), 'login_url' => wp_login_url(get_permalink()), 'text' => array( 'success' => 'Điểm danh thành công!', 'already_checked' => 'Bạn đã điểm danh hôm nay rồi!', 'come_back' => 'Hãy quay lại vào ngày mai!', 'streak_bonus' => 'Thưởng chuỗi điểm danh liên tiếp!', 'points_earned' => 'Bạn đã nhận được %d điểm!', 'total_points' => 'Tổng điểm hiện tại: %d', 'redeem_success' => 'Đổi mã giảm giá thành công!', 'not_enough_points' => 'Bạn không đủ điểm để đổi mã giảm giá!', 'coupon_code' => 'Mã giảm giá của bạn là: %s', 'login_required' => 'Vui lòng đăng nhập để điểm danh!', 'error' => 'Đã xảy ra lỗi, vui lòng thử lại sau!', ) )); } add_action('wp_enqueue_scripts', 'register_daily_checkin_assets'); // Khởi tạo hệ thống điểm danh function init_daily_checkin_system() { // Tạo bảng lưu trữ dữ liệu điểm danh nếu chưa tồn tại global $wpdb; $charset_collate = $wpdb->get_charset_collate(); // Bảng lưu trữ lịch sử điểm danh $table_checkin_history = $wpdb->prefix . 'daily_checkin_history'; $sql_history = "CREATE TABLE $table_checkin_history ( id bigint(20) NOT NULL AUTO_INCREMENT, user_id bigint(20) NOT NULL, check_date date NOT NULL, points int(11) NOT NULL DEFAULT 0, streak int(11) NOT NULL DEFAULT 0, PRIMARY KEY (id), UNIQUE KEY user_date (user_id, check_date) ) $charset_collate;"; // Bảng lưu trữ thông tin điểm thưởng của người dùng $table_user_points = $wpdb->prefix . 'daily_checkin_user_points'; $sql_points = "CREATE TABLE $table_user_points ( id bigint(20) NOT NULL AUTO_INCREMENT, user_id bigint(20) NOT NULL, total_points int(11) NOT NULL DEFAULT 0, current_streak int(11) NOT NULL DEFAULT 0, last_checkin date DEFAULT NULL, PRIMARY KEY (id), UNIQUE KEY user_id (user_id) ) $charset_collate;"; // Bảng lưu trữ lịch sử đổi mã giảm giá $table_coupon_history = $wpdb->prefix . 'daily_checkin_coupon_history'; $sql_coupons = "CREATE TABLE $table_coupon_history ( id bigint(20) NOT NULL AUTO_INCREMENT, user_id bigint(20) NOT NULL, coupon_code varchar(50) NOT NULL, points_used int(11) NOT NULL, created_at datetime NOT NULL, used tinyint(1) NOT NULL DEFAULT 0, PRIMARY KEY (id) ) $charset_collate;"; // Bảng lưu trữ cài đặt hệ thống $table_settings = $wpdb->prefix . 'daily_checkin_settings'; $sql_settings = "CREATE TABLE $table_settings ( id bigint(20) NOT NULL AUTO_INCREMENT, setting_name varchar(100) NOT NULL, setting_value text NOT NULL, PRIMARY KEY (id), UNIQUE KEY setting_name (setting_name) ) $charset_collate;"; require_once(ABSPATH . 'wp-admin/includes/upgrade.php'); dbDelta($sql_history); dbDelta($sql_points); dbDelta($sql_coupons); dbDelta($sql_settings); // Thêm cài đặt mặc định nếu chưa có initialize_default_settings(); } // Gọi hàm này một lần để khởi tạo database add_action('init', 'init_daily_checkin_system'); |
Hệ Thống Cài Đặt Và Xử Lý Điểm Danh Trong WordPress
Để vận hành hệ thống điểm danh, bạn cần khởi tạo cài đặt mặc định như số điểm mỗi lần điểm danh, thưởng chuỗi ngày liên tiếp, cấu hình đổi mã giảm giá, và hiển thị giao diện. Các cài đặt này được lưu trữ vào bảng daily_checkin_settings và có thể dễ dàng truy xuất hoặc cập nhật thông qua các hàm get_checkin_setting() và update_checkin_setting().





Hàm handle_daily_checkin() đảm nhiệm việc xử lý AJAX điểm danh: kiểm tra đăng nhập, xác thực nonce, kiểm tra đã điểm danh hôm nay chưa, tính điểm và thưởng chuỗi nếu đủ điều kiện. Người dùng sẽ nhận điểm tự động và hệ thống sẽ lưu lại lịch sử điểm danh vào database.
✅ Tự động hóa, dễ cấu hình, hỗ trợ phát triển hệ thống tương tác người dùng bền vững trên nền WordPress.
|
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 |
// Thiết lập cài đặt mặc định function initialize_default_settings() { global $wpdb; $table_settings = $wpdb->prefix . 'daily_checkin_settings'; $default_settings = array( 'points_per_checkin' => 10, 'streak_bonus_points' => json_encode(array( '5' => 10, // 5 ngày liên tiếp: +10 điểm '10' => 20, // 10 ngày liên tiếp: +20 điểm '15' => 30, // 15 ngày liên tiếp: +30 điểm '30' => 50, // 30 ngày liên tiếp: +50 điểm )), 'points_for_coupon' => json_encode(array( '100' => array('discount' => 5, 'type' => 'percent'), // 100 điểm: 5% giảm giá '200' => array('discount' => 10, 'type' => 'percent'), // 200 điểm: 10% giảm giá '500' => array('discount' => 20, 'type' => 'percent'), // 500 điểm: 20% giảm giá '1000' => array('discount' => 50, 'type' => 'fixed'), // 1000 điểm: 50.000đ giảm giá )), 'coupon_expire_days' => 30, // Hạn sử dụng mã giảm giá: 30 ngày 'display_settings' => json_encode(array( 'theme_color' => '#4e73df', 'secondary_color' => '#1cc88a', 'background_image' => '', 'animation' => 'fade', 'show_leaderboard' => true, 'leaderboard_limit' => 10, )), ); foreach ($default_settings as $name => $value) { $wpdb->replace( $table_settings, array( 'setting_name' => $name, 'setting_value' => is_array($value) || is_object($value) ? json_encode($value) : $value, ), array('%s', '%s') ); } } // Lấy cài đặt từ database function get_checkin_setting($setting_name, $default = null) { global $wpdb; $table_settings = $wpdb->prefix . 'daily_checkin_settings'; $value = $wpdb->get_var($wpdb->prepare( "SELECT setting_value FROM $table_settings WHERE setting_name = %s", $setting_name )); if ($value === null) { return $default; } // Tự động chuyển đổi JSON thành array nếu cần if (in_array($setting_name, array('streak_bonus_points', 'points_for_coupon', 'display_settings'))) { return json_decode($value, true); } return $value; } // Cập nhật cài đặt function update_checkin_setting($setting_name, $value) { global $wpdb; $table_settings = $wpdb->prefix . 'daily_checkin_settings'; // Chuyển đổi array thành JSON nếu cần if (is_array($value) || is_object($value)) { $value = json_encode($value); } return $wpdb->replace( $table_settings, array( 'setting_name' => $setting_name, 'setting_value' => $value, ), array('%s', '%s') ); } // Xử lý AJAX cho điểm danh hàng ngày function handle_daily_checkin() { // Kiểm tra nonce if (!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'daily_checkin_nonce')) { wp_send_json_error(array('message' => 'Lỗi bảo mật!')); } // Kiểm tra đăng nhập if (!is_user_logged_in()) { wp_send_json_error(array( 'message' => 'Vui lòng đăng nhập để điểm danh!', 'login_url' => wp_login_url(get_permalink()) )); } $user_id = get_current_user_id(); $today = current_time('Y-m-d'); global $wpdb; $history_table = $wpdb->prefix . 'daily_checkin_history'; $points_table = $wpdb->prefix . 'daily_checkin_user_points'; // Kiểm tra xem đã điểm danh hôm nay chưa $already_checked = $wpdb->get_var($wpdb->prepare( "SELECT COUNT(*) FROM $history_table WHERE user_id = %d AND check_date = %s", $user_id, $today )); if ($already_checked > 0) { wp_send_json_error(array( 'message' => 'Bạn đã điểm danh hôm nay rồi!', 'next_checkin' => date('Y-m-d H:i:s', strtotime('tomorrow')), )); } // Lấy thông tin điểm thưởng hiện tại $user_points = $wpdb->get_row($wpdb->prepare( "SELECT * FROM $points_table WHERE user_id = %d", $user_id )); // Tính toán chuỗi điểm danh liên tiếp (streak) $streak = 1; $streak_bonus = 0; $points_per_checkin = intval(get_checkin_setting('points_per_checkin', 10)); $total_points = $points_per_checkin; if ($user_points) { // Kiểm tra xem ngày hôm qua đã điểm danh chưa $last_checkin = new DateTime($user_points->last_checkin); $yesterday = new DateTime('yesterday'); if ($last_checkin->format('Y-m-d') === $yesterday->format('Y-m-d')) { // Điểm danh liên tiếp $streak = $user_points->current_streak + 1; } else { // Chuỗi điểm danh bị đứt $streak = 1; } // Tổng điểm hiện tại $total_points = $user_points->total_points + $points_per_checkin; } // Kiểm tra xem có được thưởng thêm điểm cho chuỗi điểm danh liên tiếp không $streak_bonuses = get_checkin_setting('streak_bonus_points', array()); $bonus_message = ''; if (isset($streak_bonuses[$streak])) { $streak_bonus = intval($streak_bonuses[$streak]); $total_points += $streak_bonus; $bonus_message = sprintf( 'Chúc mừng! Bạn đã điểm danh liên tiếp %d ngày và nhận được %d điểm thưởng!', $streak, $streak_bonus ); } |
Hệ Thống Điểm Danh Hằng Ngày cho WordPress + WooCommerce
Plugin này cung cấp một hệ thống điểm danh thưởng điểm tích lũy, cho phép người dùng đăng nhập và điểm danh mỗi ngày để nhận điểm, sau đó đổi điểm lấy mã giảm giá WooCommerce. Plugin bao gồm:
🧩 Các Chức Năng Chính
-
Điểm Danh Hằng Ngày (AJAX)
-
Tự động kiểm tra và ghi nhận điểm danh mỗi ngày.
-
Hệ thống chuỗi điểm danh liên tiếp, thưởng bonus ở các mốc 5, 10, 15, 30 ngày.
-
Lưu lịch sử vào bảng
daily_checkin_history.
-
-
Tích Lũy & Quản Lý Điểm Thưởng
-
Lưu trữ điểm và chuỗi ngày vào
daily_checkin_user_points. -
Cập nhật số điểm theo thời gian và theo bonus streak.
-
-
Đổi Điểm Lấy Mã Giảm Giá (WooCommerce)
-
Người dùng có thể đổi điểm lấy coupon theo các mốc tùy chỉnh (100 điểm = 5%, 1000 điểm = 50k,…).
-
Tự động tạo coupon WooCommerce kèm ngày hết hạn và giới hạn sử dụng.
-
Lưu lịch sử đổi vào bảng
daily_checkin_coupon_history.
-
-
Giao Diện Shortcode Đẹp Mắt
[daily_checkin]-
Hiển thị lịch điểm danh tháng hiện tại.
-
Nút điểm danh + hiệu ứng animation.
-
Hiển thị thông tin điểm, chuỗi ngày, phần thưởng và bảng xếp hạng top người dùng.
-
-
Tùy Chỉnh Giao Diện & Logic Thưởng
-
Tùy chỉnh dễ dàng qua bảng
daily_checkin_settings:-
Màu sắc, hình nền, hiệu ứng animation, leaderboard, v.v.
-
Các mốc thưởng chuỗi, cấu trúc điểm, loại mã giảm giá.
-
-
Tích Hợp & Cấu Trúc Mã
-
AJAX xử lý với
wp_ajax_+wp_localize_script. -
Tạo bảng dữ liệu khi khởi tạo với
dbDelta. -
Tích hợp WooCommerce bằng
wp_insert_post()vàupdate_post_meta().
|
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 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 |
// Lưu lịch sử điểm danh $wpdb->insert( $history_table, array( 'user_id' => $user_id, 'check_date' => $today, 'points' => $points_per_checkin + $streak_bonus, 'streak' => $streak, ), array('%d', '%s', '%d', '%d') ); // Cập nhật thông tin điểm thưởng if ($user_points) { $wpdb->update( $points_table, array( 'total_points' => $total_points, 'current_streak' => $streak, 'last_checkin' => $today, ), array('user_id' => $user_id), array('%d', '%d', '%s'), array('%d') ); } else { $wpdb->insert( $points_table, array( 'user_id' => $user_id, 'total_points' => $total_points, 'current_streak' => $streak, 'last_checkin' => $today, ), array('%d', '%d', '%d', '%s') ); } // Trả về kết quả wp_send_json_success(array( 'message' => 'Điểm danh thành công!', 'points_earned' => $points_per_checkin, 'streak_bonus' => $streak_bonus, 'streak_bonus_message' => $bonus_message, 'total_points' => $total_points, 'current_streak' => $streak, 'next_checkin' => date('Y-m-d H:i:s', strtotime('tomorrow')), )); } add_action('wp_ajax_daily_checkin', 'handle_daily_checkin'); add_action('wp_ajax_nopriv_daily_checkin', 'handle_daily_checkin'); // Xử lý AJAX cho đổi điểm lấy mã giảm giá function handle_redeem_points() { // Kiểm tra nonce if (!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'daily_checkin_nonce')) { wp_send_json_error(array('message' => 'Lỗi bảo mật!')); } // Kiểm tra đăng nhập if (!is_user_logged_in()) { wp_send_json_error(array( 'message' => 'Vui lòng đăng nhập để đổi điểm!', 'login_url' => wp_login_url(get_permalink()) )); } // Kiểm tra tham số bắt buộc if (!isset($_POST['points_to_redeem']) || !is_numeric($_POST['points_to_redeem'])) { wp_send_json_error(array('message' => 'Số điểm không hợp lệ!')); } $user_id = get_current_user_id(); $points_to_redeem = intval($_POST['points_to_redeem']); global $wpdb; $points_table = $wpdb->prefix . 'daily_checkin_user_points'; $coupon_table = $wpdb->prefix . 'daily_checkin_coupon_history'; // Lấy thông tin điểm thưởng hiện tại $user_points = $wpdb->get_row($wpdb->prepare( "SELECT * FROM $points_table WHERE user_id = %d", $user_id )); if (!$user_points || $user_points->total_points < $points_to_redeem) { wp_send_json_error(array('message' => 'Bạn không đủ điểm để đổi mã giảm giá này!')); } // Lấy thông tin mã giảm giá tương ứng với số điểm $coupon_settings = get_checkin_setting('points_for_coupon', array()); if (!isset($coupon_settings[$points_to_redeem])) { wp_send_json_error(array('message' => 'Mã giảm giá này không tồn tại!')); } $coupon_info = $coupon_settings[$points_to_redeem]; $discount = $coupon_info['discount']; $discount_type = $coupon_info['type']; // Tạo mã giảm giá trong WooCommerce nếu có $coupon_code = ''; if (function_exists('WC')) { $coupon_code = 'CHECKIN_' . $user_id . '_' . uniqid(); $coupon = array( 'post_title' => $coupon_code, 'post_content' => '', 'post_status' => 'publish', 'post_author' => 1, 'post_type' => 'shop_coupon' ); $new_coupon_id = wp_insert_post($coupon); // Thiết lập dữ liệu cho mã giảm giá update_post_meta($new_coupon_id, 'discount_type', $discount_type === 'percent' ? 'percent' : 'fixed_cart'); update_post_meta($new_coupon_id, 'coupon_amount', $discount); update_post_meta($new_coupon_id, 'individual_use', 'yes'); update_post_meta($new_coupon_id, 'usage_limit', '1'); update_post_meta($new_coupon_id, 'usage_limit_per_user', '1'); // Thời gian hết hạn $expire_days = intval(get_checkin_setting('coupon_expire_days', 30)); $expiry_date = date('Y-m-d', strtotime("+$expire_days days")); update_post_meta($new_coupon_id, 'date_expires', strtotime($expiry_date)); // Giới hạn cho một người dùng update_post_meta($new_coupon_id, 'customer_email', array(get_userdata($user_id)->user_email)); } else { // Nếu không có WooCommerce, tạo mã giảm giá đơn giản $coupon_code = 'CHECKIN_' . $user_id . '_' . substr(md5(uniqid(mt_rand(), true)), 0, 8); } // Cập nhật điểm thưởng $wpdb->update( $points_table, array('total_points' => $user_points->total_points - $points_to_redeem), array('user_id' => $user_id), array('%d'), array('%d') ); // Lưu lịch sử đổi mã giảm giá $wpdb->insert( $coupon_table, array( 'user_id' => $user_id, 'coupon_code' => $coupon_code, 'points_used' => $points_to_redeem, 'created_at' => current_time('mysql'), ), array('%d', '%s', '%d', '%s') ); // Tạo thông báo $coupon_message = sprintf( 'Bạn đã đổi thành công %d điểm lấy mã giảm giá %s%s.', $points_to_redeem, $discount, $discount_type === 'percent' ? '%' : ' VNĐ' ); // Trả về kết quả wp_send_json_success(array( 'message' => 'Đổi mã giảm giá thành công!', 'coupon_code' => $coupon_code, 'coupon_message' => $coupon_message, 'points_used' => $points_to_redeem, 'remaining_points' => $user_points->total_points - $points_to_redeem, 'expire_days' => intval(get_checkin_setting('coupon_expire_days', 30)), )); } add_action('wp_ajax_redeem_points', 'handle_redeem_points'); add_action('wp_ajax_nopriv_redeem_points', 'handle_redeem_points'); // Shortcode hiển thị form điểm danh function daily_checkin_shortcode($atts) { $atts = shortcode_atts(array( 'title' => 'Điểm Danh Hàng Ngày', 'description' => 'Điểm danh mỗi ngày để nhận điểm thưởng!', ), $atts); // Kiểm tra đăng nhập if (!is_user_logged_in()) { return '<div class="daily-checkin-container"> <div class="daily-checkin-login-required"> <h3>' . esc_html($atts['title']) . '</h3> <p>' . esc_html($atts['description']) . '</p> <a href="' . esc_url(wp_login_url(get_permalink())) . '" class="daily-checkin-login-btn">Đăng nhập để điểm danh</a> </div> </div>'; } // Enqueue scripts and styles wp_enqueue_script('sweetalert2'); wp_enqueue_style('sweetalert2'); wp_enqueue_script('daily-checkin'); wp_enqueue_style('daily-checkin'); $user_id = get_current_user_id(); $user_data = get_userdata($user_id); $today = current_time('Y-m-d'); global $wpdb; $history_table = $wpdb->prefix . 'daily_checkin_history'; $points_table = $wpdb->prefix . 'daily_checkin_user_points'; // Kiểm tra xem đã điểm danh hôm nay chưa $already_checked = $wpdb->get_var($wpdb->prepare( "SELECT COUNT(*) FROM $history_table WHERE user_id = %d AND check_date = %s", $user_id, $today )); // Lấy thông tin điểm thưởng hiện tại $user_points = $wpdb->get_row($wpdb->prepare( "SELECT * FROM $points_table WHERE user_id = %d", $user_id )); $current_points = $user_points ? $user_points->total_points : 0; $current_streak = $user_points ? $user_points->current_streak : 0; // Lấy lịch sử điểm danh trong tháng $month_start = date('Y-m-01'); $month_end = date('Y-m-t'); $month_history = $wpdb->get_results($wpdb->prepare( "SELECT check_date, points, streak FROM $history_table WHERE user_id = %d AND check_date BETWEEN %s AND %s ORDER BY check_date ASC", $user_id, $month_start, $month_end )); // Tạo mảng ngày trong tháng $month_dates = array(); $current_date = new DateTime($month_start); $end_date = new DateTime($month_end); while ($current_date <= $end_date) { $month_dates[$current_date->format('Y-m-d')] = array( 'checked' => false, 'points' => 0, 'streak' => 0, ); $current_date->modify('+1 day'); } // Cập nhật lịch sử điểm danh foreach ($month_history as $history) { if (isset($month_dates[$history->check_date])) { $month_dates[$history->check_date]['checked'] = true; $month_dates[$history->check_date]['points'] = $history->points; $month_dates[$history->check_date]['streak'] = $history->streak; } } // Lấy thông tin mã giảm giá $coupon_settings = get_checkin_setting('points_for_coupon', array()); $display_settings = get_checkin_setting('display_settings', array()); // Sắp xếp theo số điểm tăng dần ksort($coupon_settings); // Tạo HTML cho form điểm danh $output = '<div class="daily-checkin-container" style="--theme-color: ' . esc_attr($display_settings['theme_color']) . '; --secondary-color: ' . esc_attr($display_settings['secondary_color']) . ';">'; // Header $output .= '<div class="daily-checkin-header"> <h2>' . esc_html($atts['title']) . '</h2> <p>' . esc_html($atts['description']) . '</p> </div>'; // Thông tin người dùng $output .= '<div class="daily-checkin-user-info"> <div class="user-avatar">' . get_avatar($user_id, 64) . '</div> <div class="user-details"> <h3>' . esc_html($user_data->display_name) . '</h3> <div class="user-stats"> <div class="stats-item"> <span class="stats-label">Điểm hiện tại:</span> <span class="stats-value">' . esc_html($current_points) . '</span> </div> <div class="stats-item"> <span class="stats-label">Chuỗi điểm danh:</span> <span class="stats-value">' . esc_html($current_streak) . ' ngày</span> </div> </div> </div> </div>'; // Lịch điểm danh $output .= '<div class="daily-checkin-calendar"> <h3>Lịch điểm danh tháng ' . date('m/Y') . '</h3> <div class="calendar-grid">'; // Tên các ngày trong tuần $days_of_week = array('CN', 'T2', 'T3', 'T4', 'T5', 'T6', 'T7'); foreach ($days_of_week as $day) { $output .= '<div class="calendar-day-name">' . $day . '</div>'; } // Điền ngày trống trước ngày đầu tiên của tháng $first_day_of_month = date('w', strtotime($month_start)); for ($i = 0; $i < $first_day_of_month; $i++) { $output .= '<div class="calendar-day empty"></div>'; } // Điền các ngày trong tháng foreach ($month_dates as $date => $info) { $day_class = 'calendar-day'; $day_number = date('d', strtotime($date)); if ($info['checked']) { $day_class .= ' checked'; } if ($date === $today) { $day_class .= ' today'; } if (strtotime($date) > strtotime($today)) { $day_class .= ' future'; } $day_tooltip = ''; if ($info['checked']) { $day_tooltip = 'data-tooltip="' . esc_attr(sprintf('Đã điểm danh: +%d điểm', $info['points'])) . '"'; } $output .= '<div class="' . $day_class . '" ' . $day_tooltip . '>' . $day_number; if ($info['checked']) { $output .= '<span class="checked-mark"><i class="fas fa-check-circle"></i></span>'; } $output .= '</div>'; } $output .= '</div>'; // Kết thúc calendar-grid $output .= '</div>'; // Kết thúc daily-checkin-calendar // Nút điểm danh $output .= '<div class="daily-checkin-action">'; if ($already_checked) { $output .= '<button class="daily-checkin-btn checked" disabled>Đã điểm danh hôm nay</button>'; $output .= '<div class="next-checkin">Quay lại vào ngày mai!</div>'; } else { $output .= '<button class="daily-checkin-btn" id="daily-checkin-button">Điểm danh ngay</button>'; } $output .= '</div>'; // Kết thúc daily-checkin-action // Đổi điểm thưởng $output .= '<div class="daily-checkin-rewards"> <h3>Đổi điểm thưởng</h3> <div class="rewards-grid">'; foreach ($coupon_settings as $points => $coupon_info) { $disabled = $current_points < $points ? 'disabled' : ''; $reward_class = $current_points < $points ? 'reward-item disabled' : 'reward-item'; $discount = $coupon_info['discount']; $discount_type = $coupon_info['type']; $discount_text = $discount_type === 'percent' ? $discount . '%' : number_format($discount, 0, ',', '.') . ' VNĐ'; $output .= '<div class="' . $reward_class . '"> <div class="reward-points">' . number_format($points, 0, ',', '.') . ' điểm</div> <div class="reward-content"> <span class="reward-label">Mã giảm giá</span> <span class="reward-value">' . $discount_text . '</span> </div> <button class="redeem-btn" data-points="' . $points . '" ' . $disabled . '>Đổi ngay</button> </div>'; } $output .= '</div>'; // Kết thúc rewards-grid $output .= '</div>'; // Kết thúc daily-checkin-rewards // Hiển thị bảng xếp hạng nếu được bật if (isset($display_settings['show_leaderboard']) && $display_settings['show_leaderboard']) { $limit = isset($display_settings['leaderboard_limit']) ? intval($display_settings['leaderboard_limit']) : 10; $leaderboard = $wpdb->get_results($wpdb->prepare( "SELECT u.ID, u.display_name, p.total_points, p.current_streak FROM $points_table p JOIN {$wpdb->users} u ON p.user_id = u.ID ORDER BY p.total_points DESC, p.current_streak DESC LIMIT %d", $limit )); $output .= '<div class="daily-checkin-leaderboard"> <h3>Bảng xếp hạng</h3> <table class="leaderboard-table"> <thead> <tr> <th>Thứ hạng</th> <th>Người dùng</th> <th>Điểm</th> <th>Chuỗi</th> </tr> </thead> <tbody>'; $rank = 1; foreach ($leaderboard as $user) { $highlight = $user->ID === $user_id ? 'highlight' : ''; $output .= '<tr class="' . $highlight . '"> <td>' . $rank . '</td> <td>' . esc_html($user->display_name) . '</td> <td>' . number_format($user->total_points, 0, ',', '.') . '</td> <td>' . $user->current_streak . ' ngày</td> </tr>'; $rank++; } $output .= '</tbody> </table> </div>'; } $output .= '</div>'; // Kết thúc daily-checkin-container return $output; } add_shortcode('daily_checkin', 'daily_checkin_shortcode'); |
Phần 2: Tích Hợp Hệ Thống Affilate điểm thưởng
Plugin điểm danh của mình cho phép người dùng đăng nhập mỗi ngày để nhận điểm. Nhưng để tăng trưởng người dùng tự nhiên, mình muốn thêm chức năng “giới thiệu bạn bè”:
-
Mỗi người dùng sẽ có mã giới thiệu riêng.
-
Khi bạn bè họ đăng ký bằng mã đó, cả hai sẽ được nhận điểm.
-
Người được giới thiệu phải điểm danh đủ X lần thì phần thưởng mới được kích hoạt

Tính năng nổi bật
✅ Tự động tạo mã giới thiệu cho user khi đăng ký
✅ Lưu mã giới thiệu bằng cookie khi người dùng nhập trên site
✅ Khi người được giới thiệu đăng ký và điểm danh đủ số lần quy định → cả 2 cùng nhận điểm
✅ Có shortcode để hiển thị mã giới thiệu, liên kết giới thiệu và thống kê (thành công, chờ duyệt, tổng điểm nhận được)
✅ Tích hợp nhẹ nhàng vào plugin có sẵn, không ảnh hưởng chức năng cũ

Cấu trúc hệ thống
Hệ thống sử dụng 2 bảng chính:
-
daily_checkin_referral_codes: lưu mã giới thiệu của từng user -
daily_checkin_referrals: lưu lịch sử người giới thiệu – người được giới thiệu, trạng thái, điểm đã thưởng
Ngoài ra mình sử dụng daily_checkin_history và daily_checkin_user_points sẵn có để cộng điểm và ghi lại.
Luồng hoạt động
-
Người dùng A copy mã giới thiệu và gửi cho B
-
Người dùng B nhập mã hoặc đăng ký từ link có
?ref=MABC123 -
Mã được lưu vào cookie trong 7 ngày
-
Khi B đăng ký → hệ thống ghi nhận A là người giới thiệu
-
B bắt đầu điểm danh mỗi ngày
-
Khi B điểm danh đủ 5 lần → hệ thống tự động cộng điểm cho A và B
Giao diện người dùng
Giao diện người dùng được tạo bằng shortcode [referral_info], hiển thị:
-
Mã giới thiệu
-
Liên kết giới thiệu
-
Thống kê lượt giới thiệu thành công, đang chờ
-
Hướng dẫn cách chia sẻ mã
Tất cả được styled sẵn, responsive, và dễ tùy chỉnh nếu bạn muốn thay đổi màu sắc, font, layout.
👉 Ngoài ra có cả [referral_input] – form nhập mã giới thiệu dành cho khách chưa đăng ký.
Một số lưu ý kỹ thuật
-
Dùng
dbDelta()để tạo bảng khi kích hoạt plugin (nên dùngregister_activation_hook()thay vìinit) -
Xử lý dữ liệu từ người dùng (POST, COOKIE) cần sanitize kỹ
-
Tăng bảo mật bằng cách dùng
noncetrong form -
Cookie có
httponly,securenếu chạy HTTPS -
Code có thể mở rộng thành REST API nếu bạn muốn tích hợp mobile/app
- Plugin Phong Thuỷ Xem Màu Hợp Với Tuổi Cho WordPress – Giải Pháp Tối Ưu Cho Website Phong Thuỷ
- [Thủ thuật wordpress] Hướng dẫn code chức năng tạo và gửi mã giảm giá tự động khi người dùng đăng ký tài khoản không dùng plugin
- Top 10 Công Cụ AI Viết Bài Đỉnh Nhất 2025
- [Thủ Thuật WordPress] Code thu gọn bài viết trong WordPress cực đẹp, đơn giản
- JavaScript SEO: Cách Giúp Website JS Nặng Trình Vẫn Lên Top Google

