Header Ads Widget

Sử dụng WP Query để lấy bài viết

Query (truy vấn) là một thuật ngữ hay dùng nhất trong WordPress để chỉ các truy vấn gửi đến cơ sở dữ liệu (database) để lấy thông tin của Post, là một tập hợp các lệnh SQL gửi đến MySQL Server nhằm lấy dữ liệu của các bài viết trên WordPress.


Cách tạo mới một query đến database thông qua class WP_Query.

Cách query  ở mỗi trang

Mặc định mỗi trang trên WordPress đều có chứa query, ví dụ ở trang chủ nó sẽ gửi query để lấy danh sách bài viết mới nhất, khi vào trang nội dung bài viết thì nó sẽ gửi query để lấy thông tin của bài viết đó dựa vào ID của bài viết (ở phần trước mình đã có nói là WordPress có thể phân tích truy vấn ở một trang dựa vào đường dẫn truy cập).
Nhưng để xem chính xác trên trang của bạn có bao nhiêu query, và nó gửi như thế nào thì cài plugin Debug Bar rồi chèn đoạn này vào wp-config.php:
01
define( 'SAVEQUERIES', true );
Sau đó bạn ra trang chủ, ấn vào nút Debug trên Admin Bar và xem ở phần WP Query chứa các thông tin như template đang thực thi query (các tập tin trong theme), loại query. Còn phần Query SQL là lệnh SQL thực thi query đó.

Kết quả của query lưu vào đâu?

Sau khi gửi query, thì chắc chắn phải có kết quả trả về của query đó. Ví dụ khi nó gửi query để lấy bài mới thì chắc chắn nó sẽ trả về các thông tin của bài mới mà query đó đang cần tìm. Và các kết quả của query sẽ được lưu vào đối tượng $wp_query.
Bây giờ, bạn hãy thử lookup cái đối tượng $wp_query bằng cách chèn đoạn code dưới đây vào cuối templatefooter.php trong theme:
01
02
03
04
05
<?php
    echo '<pre>';
    print_r ($wp_query);
    echo '</pre>';
?>
Và bây giờ, bạn có thể đi qua các bài viết hoặc các trang nào đó để xem thông tin của đối tượng $wp_querysau khi nó đã gửi query, nó sẽ bao gồm tất cả các thông tin mà nó nhận được (trường hợp nó để trống là không có), Và nếu bây giờ bạn chỉ cần xem dữ liệu của thuộc tính posts thì sửa lại code debug trỏ đến thuộc tính poststrong đối tượng $wp_query.
01
02
03
04
05
<?php
    echo '<pre>';
    print_r ($wp_query->posts);
    echo '</pre>';
?>
Ngoài ra còn có thể dùng$postsđể lấy dữ liệu
01
02
03
04
05
<?php
    echo '<pre>';
    print_r ($posts);
    echo '</pre>';
?>
Và như bạn thấy, chúng ta đã có thể xem được các thuộc tính trong đối tượng $posts là các thông tin về bài viết.
Các thuộc tính trong đối tượng $posts
Các thuộc tính trong đối tượng $posts
Tuy nhiên nếu bạn cần lấy ra, chúng ta nên lấy bằng đối tượng $post (không có chữ s ở cuối). Bây giờ bạn thử mở lại template footer.php, thử lookup cái thuộc tính post_content trong đối tượng $post xem sao nhé. Hoặc bạn có thể đặt nó ở một template bất kỳ trong theme, vào vị trí bất kỳ.
01
02
03
04
05
<?php
    echo '<pre>';
    print_r ($post->post_content);
    echo '</pre>';
?>

Sử dụng vòng lặp (loop) cho query

Và nếu bạn làm đúng khi in $post->post_content thì nó sẽ trả về nội dung của bài viết hiện tại nếu bạn vào xem nội dung một post. Nhưng nếu bạn xem ngoài trang index, hay các trang lưu trữ như tag, category,…thì nó chỉ hiển thị nội dung bài viết đầu tiên.
Bởi vì cái $post thực chất là một đối tượng trong một mảng (array), nên nếu gọi như thế thì PHP sẽ tự hiểu chúng ta chỉ muốn gọi đối tượng đầu tiên trong mảng nên khi xem ở các trang có nhiều bài viết thì nó cũng chỉ hiển thị có một bài. Và để cho nó hiển thị toàn bộ, chúng ta phải tạo vòng lặp (loop) cho cái mảng đối tượng đó để nó lấy ra nhiều bài viết. Và chúng ta sẽ lặp thông qua phương thức have_posts() trong đối tượng$wp_query.
Trước khi tìm hiểu sâu xa, chúng ta hãy tìm hiểu cấu trúc của một đoạn vòng lặp trong WordPress, và cấu trúc của nó như sau:
01
02
03
04
05
06
07
08
09
10
11
12
13
<?php
    if( $wp_query->have_posts() ) { // Nếu phương thức have_posts() trả về TRUE thì mới chạy code bên trong
        while( $wp_query->have_posts() ) { // Nếu have_posts() == TRUE thì nó mới lặp, không thì ngừng
            $wp_query->the_post(); // Thiết lập số thứ tự bài viết trong chỉ mục của query
            /*
             * Nội dung hiển thị bài viết
             */
            echo $post->post_title . '<br>';
        }
    }
?>
hoặc
01
02
03
04
05
06
07
08
09
10
<?php
    if( $wp_query->have_posts() ) : while( $wp_query->have_posts() ) : $wp_query->the_post();
            /*
             * Nội dung hiển thị bài viết
             */
            echo $post->post_title . '<br>';
        endwhile; endif;
?>
Bạn đặt cái này vào vị trí nào đó trong template như ở footer.php chẳng hạn, rồi ra ngoài trang chủ hoặc trang lưu trữ xem là bạn sẽ thấy nó gọi ra tiêu đề bài viết của nhiều bài khác nhau.

Ý nghĩa phương thức have_posts()

Phương thức have_posts() là một phương thức của class WP_Query vốn tạo ra đối tượng $wp_query. Phương thức này được khai báo trong tập tin /wp-includes/query.php
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
    /**
     * Whether there are more posts available in the loop.
     *
     * Calls action 'loop_end', when the loop is complete.
     *
     * @since 1.5.0
     * @access public
     *
     * @return bool True if posts are available, false if end of loop.
     */
    public function have_posts() {
        if ( $this->current_post + 1 < $this->post_count ) {
            return true;
        } elseif ( $this->current_post + 1 == $this->post_count && $this->post_count > 0 ) {
            /**
             * Fires once the loop has ended.
             *
             * @since 2.0.0
             *
             * @param WP_Query &$this The WP_Query instance (passed by reference).
             */
            do_action_ref_array( 'loop_end', array( &$this ) );
            // Do some cleaning up after the loop
            $this->rewind_posts();
        }
        $this->in_the_loop = false;
        return false;
    }
Ý nghĩa của phương thức này rất đơn giản, đó là nó sẽ kiểm tra xem còn bài viết nào trong query hay không. Sở dĩ nó có thể kiểm tra được là nó lấy số thứ tự của bài viết hiện tại (thuộc tính current_post) cộng thêm 1 đơn vị mà nhỏ hơn tổng số bài viết trong query (thuộc tính post_count) thì nó sẽ trả kết quả về là true. Ngược lại là FALSE.
Và đoạn này:
01
if( $wp_query->have_posts() )
nghĩa là nó kiểm tra xem nếu nó có bài viết trong query hiện tại ($wp_query) thì nó sẽ thực hiện vòng lặp bên dưới.
01
while( $wp_query->have_posts() )
Và trong vòng lặp này, nó sẽ lặp nếu thằng have_posts() trả về kết quả là true. Còn false thì nó sẽ dừng.

Phương thức the_post()

Phương thức này được khai báo ở /wp-includes/query.php
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
    /**
     * Sets up the current post.
     *
     * Retrieves the next post, sets up the post, sets the 'in the loop'
     * property to true.
     *
     * @since 1.5.0
     * @access public
     */
    public function the_post() {
        global $post;
        $this->in_the_loop = true;
        if ( $this->current_post == -1 ) // loop has just started
            /**
             * Fires once the loop is started.
             *
             * @since 2.0.0
             *
             * @param WP_Query &$this The WP_Query instance (passed by reference).
             */
            do_action_ref_array( 'loop_start', array( &$this ) );
        $post = $this->next_post();
        $this->setup_postdata( $post );
    }
Phương thức này nghĩa là nó sẽ đánh chỉ mục thứ tự cho bài viết trong vòng lặp và chức năng cụ thể là sẽ thiết lập thuộc tính in_the_loop sang true vì mặc định là false, mà nếu nó là true thì phương thức next_post() có thể thực thi nhằm lấy bài viết tiếp theo.
Vậy kết luận, phương thức này sẽ có chức năng đếm chỉ mục để gọi bài kế tiếp trong vòng lặp, nếu bạn không khai báo phương thức này trong vòng lặp thì bài viết đầu tiên sẽ bị lặp đi lặp lại mà không có điểm dừng.

$wp_query không cần khai báo trong vòng lặp

$wp_query là đối tượng chứa query mặc định trong trang, nên bạn có thể không cần gọi ra trong vòng lặp mà nó sẽ tự hiểu là bạn đang lặp query mặc định.
01
02
03
04
05
06
07
08
09
10
<?php
    if( have_posts() ) : while( have_posts() ) : the_post();
            /*
             * Nội dung hiển thị bài viết
             */
            echo $post->post_title . '<br>';
        endwhile; endif;
?>

Sử dụng template tags trong vòng lặp

Trong vòng lặp, nếu bạn cần lấy thông tin bài viết ra thì có thể không cần dùng đến đối tượng $post, mà chỉ cần khai báo các hàm template tag. Nó sẽ tự hiểu bạn lấy đối tượng trong query mà nó đang lặp (xem nội dung file /wp-includes/post-template.php để biết thêm chi tiết).
01
02
03
04
05
06
07
08
09
10
<?php
    if( have_posts() ) : while( have_posts() ) : the_post();
            /*
             * Nội dung hiển thị bài viết
             */
            the_title();
        endwhile; endif;
?>
Ví dụ một đoạn vòng lặp hoàn chỉnh
Bằng cách kết hợp với HTML, chúng ta có thể tạo ra một vòng lặp để lấy danh sách bài viết như thế này:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
<?php
    if( have_posts() ) : while ( have_posts() ) : the_post();
?> <!--Đóng PHP để viết HTML tiện hơn ở dưới-->
    <!--Nội dung một bài viết-->
    <article <?php post_class() ?> >
        <h1><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h1>
        <summary>
            <?php the_content(); ?>
        </summary>
        <footer>
            <?php the_tags(); ?>
        </footer>
    </article>
    <!--kết thúc nội dung-->
<?php endwhile; endif; // Kết thúc vòng lặp ?>

Tạo một đối tượng query mới với WP_Query

Sau khi xem phần trên thì bạn đã biết WordPress có một truy vấn mặc định trên mỗi trang được lưu trong đối tượng $wp_query. 

Cách sử dụng

Tạo mới nó vào một biến làm đối tượng và khai báo các tham số (dạng mảng) để tuỳ chỉnh lấy bài viết.
01
$my_query = new WP_Query( $args );
Trong đó, $args là biến chứa tham số. Ví dụ mình có thể khai báo tham số và tạo query thế này:
01
02
03
04
05
06
07
<?php
$args_my_query = array(
    'post_type'    =>    'post',
    'orderby'    => 'rand'
);
$my_query = new WP_Query( $args_my_query );
?>
Rồi sau đó, bạn mang cái đối tượng $my_query bỏ vào vòng lặp là được.
01
02
03
04
05
06
07
08
09
10
<?php
    if( $my_query->have_posts() ) : while( $my_query->have_posts() ) : $my_query->the_post();
            /*
             * Nội dung hiển thị bài viết
             */
            the_title();
        endwhile; endif;
?>
Danh sách các tham số của WP_Query tham khảo tại https://gist.github.com/thachpham92/d57b18cf02e3550acdb5.

Nhận xét