Lấy bài viết dựa theo Custom Field trong WordPress

Trong các bài trước ở series này, chúng ta đã tìm hiểu custom field là gì và ứng dụng của nó rồi. Chúng ta cũng đã biết rằng custom field cho phép người dùng thêm các thông tin riêng biệt vào các bài viết. Vậy sau đó thì sao? Ở bài trước, chúng ta đã tìm hiểu cách để thêm custom field một cách thủ công vào bài viết và hiển thị giá trị của custom field ra rồi. Nhưng bạn sẽ thấy thiếu sót một vấn đề đó là sao lại chưa nhắc gì đến việc phân loại và tìm kiếm bài viết theo custom field đúng không. Vậy nên, mình sẽ hướng dẫn bạn cách lấy bài viết theo giá trị của custom field trong bài viết này, cùng với đó là thử một ứng dụng rất thú vị của custom field đó chính là tìm kiếm nâng cao.

Nếu bạn truy cập vào một website có tính năng tìm kiếm như tìm kiếm khách sạn hoặc chuyến bay chẳng hạn, bạn sẽ thấy tính năng này có rất nhiều tiêu chí để lựa chọn tìm kiếm khác nhau. Đây chính là tìm kiếm nâng cao đấy.

Không giống như tính năng tìm kiếm mặc định của WordPress là cho phép người dùng tìm kiếm theo các ký tự chỉ dựa trên tiêu đề và nội dung của bài viết, thì tìm kiếm nâng cao sẽ cho phép bạn tìm kiếm theo rất nhiều tiêu chí khác nhau. Trong WordPress, chúng ta sẽ tạo ra các tiêu chí này bằng cách sử dụng custom field.

Chúng ta sẽ dùng một plugin như đã tạo ở bài viết trước, và chỉnh sửa lại một chút ở trong theme nhé.

Tip: bạn có thể kéo đến cuối bài viết để xem video hướng dẫn cách làm thay vì đọc cả bài nhé.

Lấy bài viết

Trước khi tìm hiểu xem lấy bài viết theo dữ liệu của custom fields như thế nào, thì chúng ta tìm hiểu một chút về cách lấy bài viết thông thường nhé. Có hai cách cơ bản để lấy bài viết, đó là:

  • Get_posts: Hàm này chỉ đơn giản là tạo một sự kiện cho WP_Query và trả về một mảng là các bài viết.
  • Sử dụng class WP_Query: Bằng cách này, bạn sẽ có một sự kiện cho WP_Query và bạn có thể tự thực hiện truy vấn. Bạn cũng có thể sử dụng các cách và các thuộc tính phổ biến.

Trong ví dụ này, mình sẽ cùng WP_Query. Để biết các tham số mà cách thức xây dựng của WP_Query chấp nhận, bạn có thể tham khảo ở đây.

Ví dụ: Đoạn code dưới đây lấy 2 bài viết bất kỳ trên website:

$args = array(
    'orderby' => 'rand',
    'posts_per_page' => '2',
);
$query = new WP_Query( $args );

Lấy bài viết dựa trên giá trị của custom fields

WP_Query cho phép sử dụng tham số $meta_query. Tham số này sẽ được dùng để tạo một sự kiện cho class WP_Meta_Query. Mục đích chính là để sinh ra đoạn code SQL để truy vấn các bài viết theo metadata.

Tham số này là một mảng các điều kiện cho meta. Mỗi điều kiện là một mảng và bạn có thể tạo key, giá trị, và so sánh cho các meta. Nếu các bài viết có giá trị meta thỏa mãn các điều kiện, thì chúng sẽ được trả về.

Ví dụ: Để tìm các bài viết có giá trị của field hcf_price thấp hơn 100, mình sử dụng đoạn code sau:

$args = array(
    'meta_query' => array(
        array(
            'key' => 'hcf_price',
            'value' => '100',
            'compare' => '<',
            'type' => 'NUMERIC',
        ),
    ),
);
$query = new WP_Query( $args );

Hiểu thêm về WP_Meta_Query

WP_Meta_Query là một hàm hỗ trợ cho các class truy vấn cơ bản như là WP_QueryWP_User_Query để lọc các kết quả bằng metadata của các đối tượng bằng việc tạo ra các mệnh đề phụ JOINWHERE để đính kèm các chuỗi truy vấn SQL nguyên bản.

Cách thức xây dựng của class WP_Meta_Query cho phép các tham số sau đây:

  • relation: Tùy chọn. Từ khóa của MySQL được sử dụng để gộp các mệnh đề của truy vấn lại. Bao gồm: AND, hoặc OR, mặc định được đặt là AND.
  • Một mảng trống: Tùy chọn. Một mảng chứa các tham số của mệnh đề được xếp đầu tiên, hoặc là truy vấn meta được định dạng đầy đủ.
    • key: Meta key để lọc theo;
    • value: Meta value để lọc theo;
    • compare: Các toán tử của MySQL sẽ được sử dụng để so sánh các giá trị: =, !=, >, >=, <, <=, LIKE, NOT LIKE, IN, NOT IN, BETWEEN, NOT BETWEEN, REGEXP, NOT REGEXP, RLIKE, EXISTS or NOT EXISTS, mặc định là IN khi value là một mảng, và ngược lại sẽ là =.
    • type: loại dữ liệu MySQL mà cột meta_value được CAST để so sánh, bao gồm: NUMERIC, BINARY, CHAR, DATE, DATETIME, DECIMAL, SIGNED, TIME, or UNSIGNED, mặc định là CHAR.

Tạo tìm kiếm nâng cao

Đầu tiên, bạn cần thiết lập lại plugin mà chúng ta đã tạo ở bài trước. Chúng ta có 2 cách để làm việc này và tạo tìm kiếm nâng cao, đó là:

  1. Hook vào filter pre_get_posts để thay đổi các tham số trong truy vấn chính mà người dùng WordPress sử dụng để truy vấn các kết quả trên trang tìm kiếm. Cách này được khuyến khích sử dụng. Chỉ có duy nhất một truy vấn mà các plugin cần phải thay đổi danh sách bài viết mà chúng ta hook vào. Vì vậy tính tương thích của nó khá là ổn. Tuy nhiên, kết quả trả về có thể không đáp ứng được yêu cầu của bạn vì các plugin đều có thể hook vào và thay đổi kết quả.
  2. Tạo một template cho trang và dùng WP_Query để truy vấn các bài viết và hiển thị chúng dưới dạng kết quả tìm kiếm. Cách là này khá là trực quan và đơn giản để hình dung cách mà chúng ta dùng WP_Query và custom field. Bên cạnh đó, bạn sẽ có toàn quyền kiểm soát các truy vấn cũng như là kết quả trả về.

Trong bài viết này, mình chọn cách thứ 2. Cách này giúp chúng ta hiểu sâu hơn về truy vấn và cách mà chúng ta tương tác với custom field khi thực hiện các truy vấn.

Tạo một template cho trang

Tạo một file advanced_search.php trong folder wp-content/themes/twentyseventeen/page-templates với nội dung như sau:

<?php
/**
 * Template Name: Advanced Search
 */

Sau đó, bạn tới trang Pages > Add New và tạo một trang mới với template là Advanced Search như ảnh dưới đây:

Tạo một template để phục vụ cho việc tìm kiếm nâng cao trong WordPress
Tạo một template tên là Advanced Search để hiển thị các kết quả tìm kiếm nâng cao theo giá trị của custom field

Bây giờ, chúng ta sẽ hiển thị form mẫu để tìm kiếm (ô tìm kiếm) lên template này. Bạn chỉnh sửa code của trang như sau:

<?php
/**
 * Template Name: Advanced Search
 */

get_header(); ?>

    <div class="wrap">
        <div id="primary" class="content-area">
            <main id="main" class="site-main" role="main">
                <form class="advanced-search-form">
                    <div class="form-group">
                        <label>Min Price</label>
                        <input type="number" name="min-price">
                    </div>
                    <div class="form-group">
                        <label>Max Price</label>
                        <input type="number" name="max-price">
                    </div>
                    <div class="form-group">
                        <input type="submit" value="Search">
                    </div>
                </form>
            </main><!-- #main -->
        </div><!-- #primary -->
    </div><!-- .wrap -->
<?php get_footer();

Tải lại trang này và bạn sẽ thấy ô tìm kiếm hiển thị như sau:

Hiển thị ô tìm kiếm nâng cao trong WordPress
Hiển thị ô tìm kiếm với giá trị nhỏ nhất và giá trị lớn nhất cho field Giá

Tìm kiếm theo giá trị của custom fields và hiển thị kết quả

Mặc dù đã hiển thị ô tìm kiếm, nhưng bạn chưa truy xuất ra được dữ liệu để trả về kết quả đúng. Đồng thời cũng sẽ chẳng có gì xảy ra khi bạn điền giá trị nhỏ nhất và lớn nhất vào 2 ô trên để tìm kiếm cả. Lý do là chúng ta chưa xử lý để truy vấn đến các sản phẩm có giá nằm trong khoảng giá đang tìm kiếm đó.

Để lấy giá trị nhỏ nhất / lớn nhất, chúng ta sử dụng đoạn code sau:

<?php
$min_price = $_GET['min_price'] ?: '';
$max_price = $_GET['max_price'] ?: '';

Bây giờ, sửa lại các field lại một chút như sau:

Field min_price:

<input type="number" name="min_price" value="<?php echo esc_attr( $min_price ); ?>">

Field max_price:

<input type="number" name="max_price" value="<?php echo esc_attr( $max_price ); ?>">

Bạn sẽ cần đoạn code dưới đây để hiển thị ra các kết quả tìm kiếm:

<?php if ( $min_price || $max_price ): ?>
    <div class="search-result">
        <?php
        $args = [
            'posts_per_page' => - 1,
            'meta_query' => []
        ];
        if ( $min_price ) {
            $args['meta_query'][] = [
                'key' => 'hcf_price',
                'value' => $min_price,
                'compare' => '>=',
                'type' => 'NUMERIC'
            ];
        }
        if ( $max_price ) {
            $args['meta_query'][] = [
                'key' => 'hcf_price',
                'value' => $max_price,
                'compare' => '<=',
                'type' => 'NUMERIC'
            ];
        }
        $search_query = new WP_Query( $args );
        if ( $search_query->have_posts() ):
            while ( $search_query->have_posts() ) {
                $search_query->the_post();
                get_template_part( 'template-parts/post/content', 'excerpt' );
            }
            wp_reset_postdata();
            ?>
        <?php else: ?>
            <p>No result found.</p>
        <?php endif; ?>
    </div>
<?php endif; ?>

Chú ý là có một phần các tham số được tạo dựng cho truy vấn $args dựa trên giá thấp nhất và lớn nhất trong đoạn code trên. Chúng ta sử dụng hàm so sánh <=, >= để chắc chắn rằng giá của sản phẩm nằm trong khoảng giá được lựa chọn.

Ảnh dưới đây là kết quả hiển thị ra sau khi mình nhấn vào nút Search. Bạn sẽ thấy chỉ có những sản phẩm có giá từ 1 đến 300 được hiển thị mà thôi.

Kết quả hiển thị ra khi tìm kiếm dựa vào custom field trong WordPress.

Bên cạnh hàm so sánh <=, >=, bạn có thể sử dụng rất nhiều hàm so sánh khác như là =, !=, và IN. Bạn có thể kết hợp chúng với custom field để tạo ra các truy vấn phức tạp hơn, ví dụ: tìm kiếm các sản phẩm có màu xanh, năm sản xuất sau 2012, … Bạn có thể xem thêm về các hàm so sánh ở đây.

Bạn cũng có thể tải về toàn bộ đoạn code mình sử dụng cho file advanced_search.php ở đây nhé.

Video hướng dẫn

Bạn cũng có thể xem video hướng dẫn đầy đủ cho bài viết này ở đây:

Lời kết

Mỗi truy vấn theo giá trị của custom field sẽ tạo một bản ghi JOIN trong SQL. Vì vậy, nếu bạn có hàng chục custom field, thì tốc độ truy vấn sẽ bị giảm đáng kể. Bởi vậy, nếu bạn thấy tốc độ truy vấn quá chậm, bạn nên tối ưu hoặc là cache các custom field đó lại. Ngoài ra, bạn cũng nên giới hạn số lượng các custom field được phép truy vấn.

Lưu ý là custom field không được tạo ra để truy vấn nhé. Mục đích chính của custom field vẫn là thêm dữ liệu cho bài viết. Nên nếu bạn truy vấn quá nhiều, thì hãy cân nhắc việc sử dụng custom taxonomy để thay thế nhé.

Để lại bình luận

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *