[wp-trac] [WordPress Trac] #48223: parse_request(): When request has multiple matching rewrite rules, and matched rule returns 404 - iterate to next rewrite rule

WordPress Trac noreply at wordpress.org
Wed May 6 19:12:08 UTC 2020


#48223: parse_request(): When request has multiple matching rewrite rules, and
matched rule returns 404 - iterate to next rewrite rule
------------------------------------+------------------------------
 Reporter:  apedog                  |       Owner:  (none)
     Type:  defect (bug)            |      Status:  new
 Priority:  normal                  |   Milestone:  Awaiting Review
Component:  Rewrite Rules           |     Version:
 Severity:  normal                  |  Resolution:
 Keywords:  has-patch dev-feedback  |     Focuses:
------------------------------------+------------------------------

Comment (by apedog):

 So in attempting to write a patch for this ticket I ended up having to re-
 factor class WP. So the attached patch is a little "bigger" than just a
 patch for this ticket and might justify opening a separate ticket for.

 -----

 I've added a patch (48223.wp-refactor.patch) that does multiple things.
 - Refactors class WP
 - Introduced a new class Request_Environment
 - Added code to allow parsing multiple rules if the first one returns
 empty/404

 == Request_Environment
 Request_Environment is the same as the old WP environment class but is
 decoupled from {{{$_SERVER}}}, {{{$_GET}}}, {{{$_POST}}}, {{{global
 $wp_the_query}}} etc.
 It does not send headers. It does not set globals.

 Request_Environment can ideally be used within a virtual WordPress
 environment, to parse any request string, without setting globals, without
 sending headers and using global $wp_query.

 It does not accesses {{{$_SERVER}}} and {{{global $wp_query}}} directly,
 but instead uses instance variables {{{$this->server}}},
 {{{$this->wp_query}}} etc.

 It introduces a new method {{{setup_request_environment()}}} that accepts
 {{{$_SERVER}}} (or a similarly formatted array), {{{$_GET}}}, {{{$_POST}}}
 (or equivalent array), a {{{WP_Query}}} object and a {{{WP_Rewrite}}}
 instance. And stores them to local/instance variables.

 == Refactor class WP
 WP is now an extension of Request_Environment.
 It uses the new {{{setup_request_environment()}}} method to populate
 instance variables with actual globals {{{$_SERVER}}}, {{{$_GET}}}, global
 {{{$wp_query}}}, {{{$wp_rewrites}}}.
 It also sends headers and sets globals after parsing is done as before.

 All methods that were available before are still available now. Either in
 {{{class WP}}} or in {{{class Request_Environment}}}.

 All hooks that were available before are still available now. Except some
 minor changes detailed below.

 == parse_request()
 In order to better work with the WP environment object and
 {{{parse_request()}}} method, I've broken it up into 3 separate
 chunks/methods - detailed in the section below.

 == Multiple Rules Matching
 In order to accomodate multiple rule matching (the main impetus behind
 this exercise), I've had to break up {{{parse_request()}}} into smaller
 more managable chunks:
 - {{{_match_rewrite_rules()}}}: gets all rules that match request. Does
 not break after first match and keeps them in an array.
 - {{{_match_single_rule()}}}: same algorithm as before.
 - {{{_parse_request()}}}: actual parsing of the current rule being
 matched. same as before.

 I've added a hook {{{'match_multiple_rules'}}} and a new function
 _reparse_request().
 If {{{match_multiple_rules}}} is set to {{{true}}}, and the first
 {{{query_posts()}}} returns empty or 404, {{{_reparse_request()}}} will
 clear the WP_Query object, will parse the next matching rule and
 query_posts again.

 == Notable Changes
 I've changed the order of query_posts() and send_headers(). So headers are
 only sent after query_posts ( and reparse_request ) have run. This means
 some hooks will now fire in a slightly different order. This might cause
 problems in some rare edge-cases. But I believe this is a minor change
 that should not break any existing installaiton or plugin.
 But if testing proves this assumption wrong - reverting it shouldn't be
 too hard to do. It will just require slightly repetitive code.

 {{{unset($_GET['error'])}}} now executes inside {{{setup_globals()}}} -
 after {{{_reparse_request()}}} finishes  - and not during
 {{{parse_request()}}} as before.

 ----

 This might need some further iterations. But it generally works. I'd love
 to get some feedback on this. And am willing to shepherd this ticket and
 make changes if necessary. I know this might be/seem to be a big change so
 any and all feedback is appreciated.


 @SergeyBiryukov I know you've made some changes to class-wp recently. This
 applies cleanly to that AFAICT. But obviously this needs scrutiny.
 @johnbillion - You've expressed some interest in this type of
 functionality. This is what I came up with. I'd greatly appreciate your
 input as well.

-- 
Ticket URL: <https://core.trac.wordpress.org/ticket/48223#comment:4>
WordPress Trac <https://core.trac.wordpress.org/>
WordPress publishing platform


More information about the wp-trac mailing list