Hãy để tôi giải thích việc xử lý yêu cầu của WordPress và phương pháp thay đổi hành vi của WordPress để hoàn thành mục tiêu của bạn.
Phân tích yêu cầu
Khi WordPress nhận được yêu cầu, nó bắt đầu một quá trình mổ xẻ yêu cầu và chuyển nó thành một trang. Cốt lõi của quá trình này bắt đầu khi phương thức truy vấn chính của WordPress WP::main()
được gọi. Hàm này phân tích cú pháp truy vấn, như bạn đã xác định chính xác, trong parse_request()
(in includes/class-wp.php
). Ở đó, WordPress cố gắng khớp URL với một trong các quy tắc viết lại . Khi URL được khớp, nó sẽ tạo ra một chuỗi truy vấn của các phần URL và mã hóa các phần này (mọi thứ giữa hai dấu gạch chéo) bằng cách sử dụng urlencode()
, để ngăn các ký tự đặc biệt như làm &
rối chuỗi truy vấn. Các ký tự được mã hóa này có thể khiến bạn nghĩ rằng vấn đề nằm ở đó, nhưng chúng thực sự biến thành các ký tự "thực" tương ứng của chúng khi phân tích chuỗi truy vấn.
Chạy truy vấn liên quan đến yêu cầu
Sau khi WordPress phân tích cú pháp URL, nó sẽ thiết lập lớp truy vấn chính WP_Query
, được thực hiện theo cùng một main()
phương thức của WP
lớp. Thịt bò của WP_Query
có thể được tìm thấy trong get_posts()
phương thức của nó trong đó tất cả các đối số truy vấn được phân tích cú pháp và khử trùng và truy vấn SQL thực tế được xây dựng (và cuối cùng, chạy).
Trong phương thức này, trên dòng 2730, đoạn mã sau được thực thi:
$q['name'] = sanitize_title_for_query( $q['name'] );
Điều này vệ sinh bài đăng để lấy nó từ bảng bài viết. Xuất thông tin gỡ lỗi bên trong vòng lặp cho thấy đây là nơi giải quyết vấn đề: tên bài đăng của bạn my-permalink~
, được chuyển thành my-permalink
, sau đó được sử dụng để lấy bài đăng từ cơ sở dữ liệu.
Chức năng vệ sinh tiêu đề bài
Hàm sanitize_title_for_query
gọi sanitize_title
với các tham số thích hợp, tiến hành vệ sinh tiêu đề. Bây giờ cốt lõi của chức năng này là áp dụng sanitize_title
bộ lọc:
$title = apply_filters( 'sanitize_title', $title, $raw_title, $context );
Bộ lọc này, trong WordPress nguyên gốc, có một chức năng duy nhất được đính kèm với nó : sanitize_title_with_dashes
. Tôi đã viết một cái nhìn bao quát về chức năng này, có thể tìm thấy ở đây . Trong chức năng này, dòng gây ra vấn đề của bạn là
$title = preg_replace('/[^%a-z0-9 _-]/', '', $title);
Dòng này loại bỏ tất cả các ký tự ngoại trừ các ký tự chữ và số, dấu cách, dấu gạch nối và dấu gạch dưới.
Giải quyết vấn đề của bạn
Vì vậy, về cơ bản có một cách duy nhất để giải quyết vấn đề của bạn: xóa sanitize_title_with_dashes
chức năng khỏi bộ lọc và thay thế nó bằng chức năng của riêng bạn. Điều này thực sự không khó thực hiện, nhưng :
- Khi WordPress thay đổi quy trình vệ sinh tiêu đề nội bộ, điều này sẽ có tác dụng lớn trên trang web của bạn.
- Các plugin khác móc vào bộ lọc này có thể không xử lý chính xác chức năng mới.
Quan trọng nhất : WordPress sử dụng kết quả của sanitize_title
hàm trực tiếp trong truy vấn SQL theo dòng này:
$where .= " AND $wpdb->posts.post_name = '" . $q['name'] . "'";
Nếu bạn bao giờ xem xét việc thay đổi bộ lọc, hãy chắc chắn rằng bạn thoát đúng tiêu đề trước khi sử dụng nó trong truy vấn!
Kết luận: giải quyết vấn đề của bạn là không cần thiết khi có liên quan đến bảo mật, nhưng bạn nên làm điều đó, thay thế sanitize_title_with_dashes
bằng chức năng của riêng bạn và chú ý đến việc thoát SQL.
NB tất cả tên tệp và số dòng tương ứng với các tệp WordPress 4.4.2.