Hướng dẫn chi tiết tạo Widget hiển thị bài viết theo danh mục trong WordPress là một phần quan trọng giúp tối ưu hóa trải nghiệm người dùng và tăng cường SEO cho website. Dưới đây là phân tích chi tiết và từng bước giải thích về đoạn mã code đã cho, nhằm giúp bạn hiểu rõ hơn về cách hoạt động cũng như khả năng tùy biến của widget này. Hãy cùng muathemewpgiare đi tìm hiểu kỹ hơn nhé
Đoạn code thực hiện, coppy bỏ vào funtion.php nhé.
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 |
class widget_bai_viet_theo_danh_muc extends WP_Widget { function __construct() { parent::__construct( 'widget_bai_viet_theo_danh_muc', __('Bài viết theo danh mục', 'abweb.vn'), array('description' => __('Hiện bài viết theo danh mục.', 'abweb.vn')) ); } public function widget($args, $instance) { $title = apply_filters('widget_title', $instance['title']); $category = $instance['category']; $num_posts = !empty($instance['num_posts']) ? absint($instance['num_posts']) : 5; $show_empty_category = !empty($instance['show_empty_category']); echo $args['before_widget']; if (!empty($title)) { echo $args['before_title'] . $title . $args['after_title']; } $query_args = array( 'category_name' => $category, 'posts_per_page' => $num_posts, ); if (!$show_empty_category) { $query_args['nopaging'] = true; } $recent_posts = new WP_Query($query_args); if ($recent_posts->have_posts()) { echo '<div class="bai_viet_theo_dm"><ul>'; while ($recent_posts->have_posts()) { $recent_posts->the_post(); echo '<li><a href="' . get_permalink() . '">' . get_the_post_thumbnail(null, array(75, 75)) . '<span class="rpwwt-post-title">' . get_the_title() . '</span></a></li>'; } echo '</ul></div>'; wp_reset_postdata(); } else { echo '<p>'; if (!$show_empty_category) { echo ' Chưa có bài viết trong danh mục này'; } echo '.</p>'; } echo $args['after_widget']; } public function form($instance) { $title = isset($instance['title']) ? $instance['title'] : __('Danh mục bài viết', 'abweb.vn'); $category = isset($instance['category']) ? $instance['category'] : ''; $num_posts = !empty($instance['num_posts']) ? absint($instance['num_posts']) : 5; $show_empty_category = !empty($instance['show_empty_category']); ?> <p> <label for="<?php echo $this->get_field_id('title'); ?>"><?php _e('Title:'); ?></label> <input class="widefat" id="<?php echo $this->get_field_id('title'); ?>" name="<?php echo $this->get_field_name('title'); ?>" type="text" value="<?php echo esc_attr($title); ?>"> </p> <p> <label for="<?php echo $this->get_field_id('category'); ?>"><?php _e('Category:'); ?></label> <select class="widefat" id="<?php echo $this->get_field_id('category'); ?>" name="<?php echo $this->get_field_name('category'); ?>"> <?php $categories = get_categories(); foreach ($categories as $cat) { echo '<option value="' . $cat->slug . '" ' . selected($category, $cat->slug, false) . '>' . $cat->name . '</option>'; } ?> </select> </p> <p> <label for="<?php echo $this->get_field_id('num_posts'); ?>"><?php _e('Số bài hiển thị:'); ?></label> <input class="widefat" id="<?php echo $this->get_field_id('num_posts'); ?>" name="<?php echo $this->get_field_name('num_posts'); ?>" type="number" value="<?php echo esc_attr($num_posts); ?>" min="1"> </p> <p> <input type="checkbox" id="<?php echo $this->get_field_id('show_empty_category'); ?>" name="<?php echo $this->get_field_name('show_empty_category'); ?>" <?php checked($show_empty_category); ?>> <label for="<?php echo $this->get_field_id('show_empty_category'); ?>"><?php _e('Show Empty Category'); ?></label> </p> <?php } public function update($new_instance, $old_instance) { $instance = array(); $instance['title'] = !empty($new_instance['title']) ? strip_tags($new_instance['title']) : ''; $instance['category'] = !empty($new_instance['category']) ? strip_tags($new_instance['category']) : ''; $instance['num_posts'] = !empty($new_instance['num_posts']) ? absint($new_instance['num_posts']) : 5; $instance['show_empty_category'] = !empty($new_instance['show_empty_category']) ? 1 : 0; return $instance; } } function dang_ky_widget_bai_viet_theo_dm() { register_widget('widget_bai_viet_theo_danh_muc'); } add_action('widgets_init', 'dang_ky_widget_bai_viet_theo_dm'); function css_widget_bai_viet_theo_danhmuc(){ ?> <style> .bai_viet_theo_dm ul { list-style: outside none none; margin-left: 0; margin-right: 0; padding-left: 0; padding-right: 0; } .bai_viet_theo_dm ul li { overflow: hidden; margin: 0 0 1.5em; } .bai_viet_theo_dm ul li:last-child { margin: 0; } .bai_viet_theo_dm .screen-reader-text {border: 0; clip: rect(1px, 1px, 1px, 1px); -webkit-clip-path: inset(50%); clip-path: inset(50%); height: 1px; margin: -1px; overflow: hidden; padding: 0; position: absolute !important; width: 1px; word-wrap: normal !important; word-break: normal; } .bai_viet_theo_dm .screen-reader-text:focus {background-color: #f1f1f1; border-radius: 3px; box-shadow: 0 0 2px 2px rgba(0, 0, 0, 0.6); clip: auto !important; -webkit-clip-path: none; clip-path: none; color: #21759b; display: block; font-size: 0.875rem; font-weight: 700; height: auto; right: 5px; line-height: normal; padding: 15px 23px 14px; text-decoration: none; top: 5px; width: auto; z-index: 100000; } .bai_viet_theo_dm ul li img { display: inline; float: left; margin: .3em .75em .75em 0; } #rpwwt-recent-posts-widget-with-thumbnails-2 img { max-width: 100px; width: 100%; height: auto; } #rpwwt-recent-posts-widget-with-thumbnails-3 img { width: 75px; height: 75px; } #rpwwt-recent-posts-widget-with-thumbnails-4 img { width: 75px; height: 75px; } </style> <?php } add_action('wp_head','css_widget_bai_viet_theo_danhmuc'); |
Giải thích đoạn code trên:
Class widget_bai_viet_theo_danh_muc được kế thừa từ WP_Widget, đây là class cốt lõi của WordPress dùng để tạo các widget tùy chỉnh. Khi kế thừa class này, chúng ta có thể xây dựng một widget riêng biệt với chức năng hiển thị bài viết dựa theo danh mục. Việc kế thừa class WP_Widget giúp đảm bảo widget hoạt động đúng chuẩn và tương thích với các phiên bản WordPress mới.
Trong phương thức __construct(), widget được khởi tạo với các thông tin cơ bản như tên, mô tả và slug. Đây là bước bắt buộc để WordPress nhận diện và hiển thị widget trong giao diện quản trị (Appearance -> Widgets). Đoạn code này giúp định danh và cung cấp thông tin cơ bản cho người dùng khi thêm widget vào các khu vực sidebar hoặc footer.
Phương thức widget() là nơi thực hiện việc hiển thị nội dung widget ra ngoài giao diện website. Các tham số $args và $instance được truyền vào chứa các thông tin cấu hình và cài đặt của widget. $args là mảng dữ liệu về cấu trúc HTML sẵn có của widget, trong khi $instance là dữ liệu cụ thể của từng widget khi được người dùng cấu hình.
Khi phương thức widget() chạy, đầu tiên chúng ta sử dụng apply_filters(‘widget_title’, $instance[‘title’]) để đảm bảo tiêu đề của widget có thể được thay đổi bởi các filter khác. Điều này hỗ trợ cho việc tùy biến widget title từ các plugin hoặc theme mà không cần can thiệp trực tiếp vào code. Nếu tiêu đề không trống, nó sẽ được hiển thị bên trong cặp thẻ HTML before_title và after_title.
Tiếp theo, tham số $category được lấy từ $instance[‘category’] và $num_posts là số lượng bài viết hiển thị. Giá trị mặc định là 5 nếu người dùng không nhập hoặc nhập sai dữ liệu. Đây là cách để đảm bảo widget luôn hoạt động mượt mà ngay cả khi thiếu dữ liệu đầu vào.
Đoạn code show_empty_category kiểm tra xem có hiển thị thông báo “Danh mục trống” hay không nếu trong danh mục được chọn không có bài viết nào. Nếu checkbox này được tick, danh mục trống vẫn sẽ hiển thị mà không có nội dung bên trong, tạo điều kiện để giữ giao diện website nhất quán.
Tiếp theo, đoạn code tạo truy vấn bài viết WP_Query dựa trên danh mục và số lượng bài viết đã cấu hình. category_name lấy theo slug danh mục mà người dùng chọn trong phần cấu hình widget. posts_per_page giúp giới hạn số lượng bài viết hiển thị, trong khi nopaging ngăn việc phân trang để tất cả bài viết đều được hiển thị một lần nếu có.
Khi truy vấn trả về kết quả, vòng lặp while ($recent_posts->have_posts()) sẽ thực hiện hiển thị từng bài viết. Mỗi bài viết được render dưới dạng một thẻ <li> kèm theo link dẫn đến bài viết đó và ảnh thumbnail. Hình ảnh được lấy bằng get_the_post_thumbnail() với kích thước 75x75px giúp đảm bảo hiển thị đồng bộ trên mọi bài viết.
Nếu không có bài viết nào trong danh mục, đoạn code else sẽ hiển thị dòng chữ “Chưa có bài viết trong danh mục này” nhằm thông báo cho người dùng. Điều này giúp tránh khoảng trắng không cần thiết và cải thiện UX khi trang được tải lên.
Phương thức form() chịu trách nhiệm tạo giao diện cấu hình cho widget trong trang quản trị WordPress. Các thẻ HTML <input>, <select>, và <label> được sử dụng để tạo các trường nhập liệu cho tiêu đề, danh mục và số lượng bài viết. Giao diện này giúp người dùng dễ dàng quản lý và cấu hình widget mà không cần viết code.
Việc sử dụng get_categories() trong <select> giúp tự động lấy tất cả danh mục có sẵn trên website và liệt kê chúng ra dưới dạng dropdown. Điều này tiện lợi vì người dùng chỉ cần chọn danh mục thay vì phải nhập tay, tránh sai sót và tiết kiệm thời gian.
Phương thức update() thực hiện nhiệm vụ lưu trữ dữ liệu khi người dùng nhấn nút “Lưu” trong giao diện widget. Các giá trị nhập vào sẽ được làm sạch bằng strip_tags() và absint() nhằm loại bỏ các ký tự đặc biệt, ngăn chặn mã độc và đảm bảo dữ liệu lưu vào database luôn ở định dạng an toàn.
Việc đăng ký widget được thực hiện thông qua register_widget(‘widget_bai_viet_theo_danh_muc’) trong hàm dang_ky_widget_bai_viet_theo_dm(). Hàm này sẽ được gọi thông qua hook widgets_init, giúp widget xuất hiện trong danh sách các widget có thể sử dụng trên website.
Để cải thiện giao diện hiển thị widget, chúng ta sử dụng css_widget_bai_viet_theo_danhmuc(). CSS được nhúng trực tiếp vào phần wp_head để tùy chỉnh giao diện của danh sách bài viết. Các quy tắc CSS như list-style: none loại bỏ dấu chấm đầu dòng, float: left giúp hình thumbnail căn trái và dòng chữ nằm bên phải.
Các class .bai_viet_theo_dm và .screen-reader-text được sử dụng để cải thiện accessibility, đảm bảo website thân thiện với mọi người dùng, kể cả những người sử dụng trình đọc màn hình. Điều này góp phần nâng cao trải nghiệm người dùng và đạt chuẩn SEO về khả năng truy cập.
Việc tối ưu SEO cho widget bao gồm sử dụng thẻ alt cho hình ảnh thumbnail. Alt text được tự động gán bằng tiêu đề bài viết thông qua get_the_title(). Điều này giúp công cụ tìm kiếm dễ dàng hiểu nội dung hình ảnh, cải thiện thứ hạng trên SERP.
Ngoài ra, cấu trúc URL thân thiện SEO được duy trì nhờ sử dụng get_permalink(). Từng link bài viết sẽ được hiển thị dưới dạng slug thay vì các tham số phức tạp, giúp tăng cường khả năng index và cải thiện trải nghiệm người dùng.
Cuối cùng, việc tối ưu CSS và giảm thiểu số lượng request không cần thiết là bước quan trọng để tăng tốc độ tải trang. Các đoạn CSS được viết gọn gàng, sử dụng ít hình ảnh và giữ phong cách thiết kế nhất quán, đảm bảo trang web không bị ảnh hưởng hiệu suất.