Cách tạo một virtual page trong WordPress

Khi xây dựng website, thi thoảng chúng ta sẽ cần hiển thị các custom data trong cơ sở dữ liệu. Tuy nhiên, các custom data này không phải là post và page, cũng không phải là một custom post type. Để người dùng có thể truy cập và xem các custom data trên, chúng ta cần tạo một custom URL. URL này thường được gọi là virtual page (trang ảo) bởi nó không được quản lý trong khu vực Admin của website WordPress.

Các bạn có thể bắt gặp virtual page trên các website thương mại điện tử / bán hàng online. Khi khách bấm mua hàng, website WordPress sẽ tạo một hóa đơn để người mua có thể kiểm tra lại thông tin về đơn hàng. Họ cũng có thể thanh toán hoặc in hóa đơn thành file PDF và tải về máy tính.

Chẳng hạn như đối với website metabox.io, chủ website sử dụng các virtual page để hiển thị changelog của các plugin (thường được gọi là các extension của core plugin Meta Box). Ví dụ đây là virtual page để hiển thị changelog của extension Meta Box Builder:

https://metabox.io/plugins/meta-box-builder/changelog/

Rõ ràng là các hóa đơn và changelog kể trên đều có nội dung tùy chỉnh (custom content), nhưng chúng lại chẳng phải là post, page hay custom post type trong WordPress. Các virtual page này được tạo ra vì một nhu cầu cụ thể nào đó của từng website.

Cách tạo virtual page trên WordPress website.

Các cách tạo virtual page

Có vài cách khác nhau để tạo một virtual page trong WordPress tùy thuộc vào việc bạn muốn tạo URL cho page đó như thế nào. Trong bài viết này, mình sẽ chỉ các bạn ba cách để tạo virtual page trong WordPress dựa vào cấu trúc permalink (đường dẫn cố định):

  • Cách 1: Tạo virtual page bằng URL đơn giản domain.com/?invoice_id=123.
  • Cách 2: Tạo virtual page nối vào một đường dẫn (link) có sẵn, chẳng hạn như đường dẫn tới changelog của các plugin của Meta Box (https://metabox.io/plugins/meta-box-builder/changelog/). Chúng ta sẽ cần dùng tới các rewrite endpoint API.
  • Cách 3: Tạo virtual page có custom link structure (cấu trúc đường dẫn riêng) là domain.com/download/123/. Đối với cách này, chúng ta sẽ cần dùng tới các custom rewrite rule.

Sau đây mình sẽ đi vào cụ thể từng cách:

Cách 1: Tạo virtual page bằng URL đơn giản

Đây là cách đơn giản nhất để tạo virtual page bởi bạn không cần phải dùng tới các custom rewrite rule. Thay vào đó, bạn chỉ cần lấy giá trị của biến invoice_id trên URL và hiển thị template dựa trên giá trị đó.

Lưu ý rằng biến trên URL không được giống với các biến truy vấn hiện có trong WordPress.

Để lấy một template cho URL, chúng ta sẽ hook init như sau:

add_filter( 'init', function( $template ) {
    if ( isset( $_GET['invoice_id'] ) ) {
        $invoice_id = $_GET['invoice_id'];
        include plugin_dir_path( __FILE__ ) . 'templates/invoice.php';
        die;
    }
} );

Chúng ta sẽ dùng hook init thay vì template_include để WordPress không phải truy vấn cơ sở dữ liệu để lấy các tin nhắn, qua đó giúp tăng tốc độ xử lý.

File template nằm trong danh mục templates của plugin. Nếu bạn đặt nó trong một danh mục khác hoặc trong phần bổ sung, hãy đổi đường dẫn sao cho phù hợp.

Sau khi chèn file xong, chúng ta cần chạy die để WordPress không thực thi các truy vấn và tác vụ khác (các truy vấn và tác vụ này có thể xuất ra ngoài màn hình).

Cách này rất nhanh và tiện lợi. Tuy nhiên, nhược điểm của nó là URL trông không đẹp mắt.

Cách 2: Tạo một virtual page bằng cách viết lại endpoint API

Rewrite endpoint APImột trong các rewrite rules của WordPress, nó sẽ giúp chúng ta thêm một hậu tố (endpoint) vào trong một cấu trúc đường dẫn có sẵn.

Ví dụ, đối với trang metabox.io, chủ website đã tạo một custom post type là product cho các plugin, và mỗi plugin lại có cấu trúc URL như sau:

https://metabox.io/plugins/meta-box-builder/

Bằng cách dùng endpoint, chúng ta có thể tạo một URL cho changelog như sau:

https://metabox.io/plugins/meta-box-builder/changelog/

Tại đây, /changelog/ đã được thêm vào phần cuối của một URL có sẵn để tạo ra một custom URL.

Cách làm này khá là đơn giản và tiện lợi bởi nó khiến URL được cấu trúc tốt và dễ hiểu hơn.

Để thêm một endpoint, bạn dùng hàm add_rewrite_endpoint() như sau:

add_action( 'init', function() {
    add_rewrite_endpoint( 'changelog', EP_PERMALINK );
} );

Sau đó tải các template như sau:

add_action( 'template_redirect', function() {
    global $wp_query;
    if ( ! is_singular( 'product' ) || ! isset( $wp_query->query_vars['changelog'] ) ) {
        return;
    }
    include plugin_dir_path( __FILE__ ) . 'templates/changelog.php';
    die;
} );

Mình dùng hook template_redirect thay cho init giống như ở phần trước bởi vì chúng ta cần kiểm tra xem page được tải có phải là một single product page không. Lưu ý rằng khi bạn thêm một endpoint vào một URL, tất các các thẻ template của WordPress vẫn hoạt động. Điều này rất hữu ích khi cần kiểm tra điều kiện của page.

Tương tự như ở cách 1, mình cũng chèn một file template từ thư mục templates của plugin và die để WordPres không phải thực thi các tác vụ khác.

Việc dùng endpoint khá là tiện đối với các loại nội dung liên quan đến nội dung hiện có. Tuy nhiên, cách 2 này bị giới hạn trong các cấu trúc URL hiện có và không thể tạo các custom URL structure. Để làm điều đó, hãy xem cách 3 dưới đây.

Tạo một virtual page trên website WordPress bằng cách viết lại endpoint API

Cách 3: Tạo virtual page bằng các custom rewrite rule

Giả sử chúng ta cần tạo một trang để download một hóa đơn có đường dẫn là domain.com/download/123 (123 là ID của đơn hàng). Hãy thực hiện theo các bước sau:

Bước 1: Tạo một custom rewrite rule

add_filter( 'generate_rewrite_rules', function ( $wp_rewrite ){
    $wp_rewrite->rules = array_merge(
        ['download/(\d+)/?$' => 'index.php?dl_id=$matches[1]'],
        $wp_rewrite->rules
    );
} );

Bộ lọc generate_rewrite_rules được dùng để thêm một custom rewrite rule mới vào danh sách các quy tắc (rule) hiện có của WordPress (được lưu trong $wp_rewrite->rules). Danh sách này là một mảng, và để thêm một quy tắc mới, bạn chỉ cần thêm một phần tử cho mảng là xong.

Một quy tắc được xác định bởi hai yếu tố:

  • Rewrite rule: được khai báo như biểu thức chính quy download/(\d+)/?$.
  • Các thông số khi WordPress phân tích cú pháp của quy tắc: index.php?dl_id=$matches[1]. Người dùng WordPres dùng hàm preg_match() nên các thông số được phân tích cú pháp tương tự như hàm này. Thông số $matches[1] là giá trị trong dấu ngoặc đầu tiên của rewrite rule, ví dụ như phần \d+. Giá trị của thông số này được truyền tới custom variable dl_id.

Bước 2: Thêm một custom query var vào WordPress

Sau khi phân tích cú pháp của rewrite rule như trên, giá trị của ID của hóa đơn được lưu trữ trong biến dl_id. Để giúp WordPress hiểu được biến này, chúng ta cần khai báo nó như sau:

add_filter( 'query_vars', function( $query_vars ){
    $query_vars[] = 'dl_id';
    return $query_vars;
} );

Đoạn code này sẽ thêm biến dl_id vào danh sách các query var của WordPress.

Bước 3: Tải một template

Để tải một template cho trang download, bạn dùng đoạn code dưới đây:

add_action( 'template_redirect', function(){
    $dl_id = intval( get_query_var( 'dl_id' ) );
    if ( $dl_id ) {
        include plugin_dir_path( __FILE__ ) . 'templates/download.php';
        die;
    }
} );

Chúng ta cần lấy ID của hóa đơn bằng hàm get_query_var(). Vì biến dl_id đã được khai báo ở bước 2 nên WordPress có thể hiểu, tìm và lấy được nó. Nếu URL của bạn là download.com/download/123 thì giá trị của biến dl_id123.

Sau đó, hãy tải file template tương ứng và die để WordPress không phải xử lý các tác vụ tiếp theo.

Khi so sánh với hai cách ở trên, cách 3 này phức tạp hơn. Tuy nhiên, đây là cách duy nhất để tạo một URL của riêng bạn.

Có thể bạn sẽ hỏi: Vậy thì làm thế nào để tạo một custom URL như domain.com/my-custom-url?

Điều này cũng không quá khó, hãy thử dùng đoạn code dưới đây:

add_filter( 'generate_rewrite_rules', function ( $wp_rewrite ){
    $wp_rewrite->rules = array_merge(
        ['my-custom-url/?$' => 'index.php?custom=1'],
        $wp_rewrite->rules
    );
} );
add_filter( 'query_vars', function( $query_vars ){
    $query_vars[] = 'custom';
    return $query_vars;
} );
add_action( 'template_redirect', function(){
    $custom = intval( get_query_var( 'custom' ) );
    if ( $custom ) {
        include plugin_dir_path( __FILE__ ) . 'templates/custom.php';
        die;
    }
} );

Lời cuối

Khi làm việc với các plugin, các developer sẽ thường xuyên phải tạo virtual page. Hy vọng rằng với ba cách trên đây, bạn đã có thể tự tạo một virtual page theo ý mình. Nếu bạn biết cách làm nào khác, hãy chia sẻ cho mọi người cùng biết trong phần bình luận 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 *