WordPress.org

Make WordPress Core

Ticket #18877: 36292-after-18877.diff

File 36292-after-18877.diff, 13.1 KB (added by rmccue, 4 years ago)
  • src/wp-includes/class-wp-rewrite-rule.php

     
     1<?php
     2
     3/**
     4 * Rewrite rule handler.
     5 */
     6class WP_Rewrite_Rule implements WP_Rewrite_RuleInterface {
     7        /**
     8         * Traditional query string/array.
     9         *
     10         * @var string|array `index.php`-prefixed query string, or query argument map.
     11         */
     12        public $query = null;
     13
     14        /**
     15         * Constructor.
     16         *
     17         * @param string|array $query Query string/argument map.
     18         */
     19        public function __construct( $query = null ) {
     20                if ( $query ) {
     21                        $this->query = $query;
     22                }
     23        }
     24
     25        /**
     26         * Get string representation of the rule.
     27         *
     28         * Primarily for backwards compatibility.
     29         *
     30         * @return string String representation of the rewrite rule.
     31         */
     32        public function __toString() {
     33                return is_array( $this->query ) ? 'index.php?' . build_query( $this->query ) : $this->query;
     34        }
     35
     36        /**
     37         * Should this rule skip the main query?
     38         *
     39         * @return bool
     40         */
     41        public function should_skip_main_query() {
     42                return $this->skip_main_query;
     43        }
     44
     45        /**
     46         * Parse pattern matches into query string.
     47         *
     48         * @param array $matches Regex matched groups from `$this->pattern`
     49         * @return array Query vars.
     50         */
     51        public function get_query_vars( $matches ) {
     52                if ( ! $this->query ) {
     53                        // Empty query, but ensure we run the main query anyway.
     54                        return array();
     55                }
     56
     57                // Trim the query of everything up to the '?'.
     58                $query = preg_replace( '!^.+\?!', '', $this->query );
     59
     60                // Substitute the substring matches into the query.
     61                $query = addslashes( WP_MatchesMapRegex::apply( $query, $matches ) );
     62
     63                // Parse into an array
     64                parse_str( $query, $perma_query_vars );
     65
     66                return $perma_query_vars;
     67        }
     68
     69        /**
     70         * Get verbose page match parameter.
     71         *
     72         * @return int|bool Match offset number, or false if non-verbose page pattern.
     73         */
     74        public function get_verbose_page_match() {
     75                if ( ! $this->query ) {
     76                        return false;
     77                }
     78
     79                $matches = preg_match( '/pagename=\$matches\[([0-9]+)\]/', $this->query, $varmatch );
     80                if ( ! $matches ) {
     81                        return false;
     82                }
     83
     84                return $varmatch;
     85        }
     86
     87        /**
     88         * Should we skip this rewrite rule?
     89         *
     90         * @param array $matches Regex matched groups from `$this->pattern`
     91         * @return boolean True if the rule should be skipped, false if the rule should be used.
     92         */
     93        public function should_skip( $matches ) {
     94                global $wp_rewrite;
     95
     96                if ( ! $this->query || ! $wp_rewrite->use_verbose_page_rules ) {
     97                        return false;
     98                }
     99
     100                $needs_verbose_match = preg_match( '/pagename=\$matches\[([0-9]+)\]/', $this->query, $varmatch );
     101                if ( ! $needs_verbose_match ) {
     102                        return false;
     103                }
     104
     105                // This is a verbose page match, let's check to be sure about it.
     106                $page = get_page_by_path( $matches[ $varmatch[1] ] );
     107                if ( ! $page ) {
     108                        // Page doesn't exist, skip rule.
     109                        return true;
     110                }
     111
     112                $post_status_obj = get_post_status_object( $page->post_status );
     113                if ( ! $post_status_obj->public && ! $post_status_obj->protected
     114                        && ! $post_status_obj->private && $post_status_obj->exclude_from_search ) {
     115                        // Page isn't public, skip rule.
     116                        return true;
     117                }
     118
     119                return false;
     120        }
     121}
  • src/wp-includes/class-wp-rewrite-ruleinterface.php

     
     1<?php
     2
     3interface WP_Rewrite_RuleInterface {
     4        /**
     5         * Parse pattern matches into query string.
     6         *
     7         * @param array $matches Regex matched groups from `$this->pattern`
     8         * @return array|null Query vars if required. `null` will skip the main query.
     9         */
     10        public function get_query_vars( $matches );
     11
     12        /**
     13         * Should the rule be skipped?
     14         *
     15         * A rule may be skipped if it relies on other criteria apart from the
     16         * pattern to match. For example, the page rewrite rule is skipped if the
     17         * corresponding page doesn't exist.
     18         *
     19         * @param array $matches Regex matched groups from `$this->pattern`
     20         * @return boolean True if the rule should be skipped, false if the rule should be used.
     21         */
     22        public function should_skip( $matches );
     23}
  • src/wp-includes/class-wp-rewrite.php

     
    16371637         *                            or 'bottom'. Default 'bottom'.
    16381638         */
    16391639        public function add_rule( $regex, $query, $after = 'bottom' ) {
    1640                 if ( is_array( $query ) ) {
     1640                if ( $query instanceof WP_Rewrite_RuleInterface ) {
     1641                        // Rule objects are for internal rewrites only.
    16411642                        $external = false;
     1643                } elseif ( is_array( $query ) ) {
     1644                        $external = false;
    16421645                        $query = add_query_arg( $query, 'index.php' );
    16431646                } else {
    16441647                        $index = false === strpos( $query, '?' ) ? strlen( $query ) : strpos( $query, '?' );
     
    16511654                if ( $external ) {
    16521655                        $this->add_external_rule( $regex, $query );
    16531656                } else {
     1657                        // Upgrade to rule object
     1658                        $rule = $query;
     1659                        if ( ! ( $rule instanceof WP_Rewrite_RuleInterface ) ) {
     1660                                $rule = new WP_Rewrite_Rule( $query );
     1661                        }
     1662
    16541663                        if ( 'bottom' == $after ) {
    1655                                 $this->extra_rules = array_merge( $this->extra_rules, array( $regex => $query ) );
     1664                                $this->extra_rules = array_merge( $this->extra_rules, array( $regex => $rule ) );
    16561665                        } else {
    1657                                 $this->extra_rules_top = array_merge( $this->extra_rules_top, array( $regex => $query ) );
     1666                                $this->extra_rules_top = array_merge( $this->extra_rules_top, array( $regex => $rule ) );
    16581667                        }
    16591668                }
    16601669        }
     
    19381947        }
    19391948
    19401949        /**
     1950         * Get the rewrite rule that matches a request.
     1951         *
     1952         * @since 4.6.0
     1953         *
     1954         * @param string $requested_path  The URL path to match against.
     1955         * @param string $requested_file  The requested file, for PATHINFO links.
     1956         * @return array|false $rewritten If a rule matches, an array containing
     1957         *                                the match and the query.
     1958         *                                False otherwise.
     1959         */
     1960        public function get_rewrite_rule_for_request( $requested_path, $requested_file ) {
     1961                $rewrite_rules = $this->wp_rewrite_rules();
     1962                if ( empty( $rewrite_rules ) ) {
     1963                        return false;
     1964                }
     1965
     1966                // Look for matches.
     1967                $request_match = $requested_path;
     1968                if ( empty( $request_match ) ) {
     1969                        // An empty request could only match against ^$ regex
     1970                        if ( isset( $rewrite['$'] ) ) {
     1971                                $rule = $rewrite['$'];
     1972
     1973                                // Upgrade rule to an object if required.
     1974                                if ( is_string( $rule ) || is_array( $rule ) ) {
     1975                                        $rule = new WP_Rewrite_Rule( $rewrite['$'] );
     1976                                }
     1977
     1978                                return array( '$', $rule, array( '' ) );
     1979                        }
     1980
     1981                        // Empty request, and no ^$ rule.
     1982                        return false;
     1983                }
     1984
     1985                foreach ( (array) $rewrite_rules as $match => $rule ) {
     1986                        // If the requested file is the anchor of the match, prepend it to the path info.
     1987                        if ( ! empty( $requested_file ) && strpos( $match, $requested_file ) === 0
     1988                                && $requested_file != $requested_path ) {
     1989                                $request_match = $requested_file . '/' . $requested_path;
     1990                        }
     1991
     1992                        if ( preg_match( "#^$match#", $request_match, $matches ) ||
     1993                                preg_match( "#^$match#", urldecode( $request_match ), $matches ) ) {
     1994
     1995                                // Upgrade rule to an object if required.
     1996                                if ( is_string( $rule ) || is_array( $rule ) ) {
     1997                                        $rule = new WP_Rewrite_Rule( $rule );
     1998                                }
     1999
     2000                                if ( $rule->should_skip( $matches ) ) {
     2001                                        continue;
     2002                                }
     2003
     2004                                // Got a match.
     2005                                return array( $match, $rule, $matches );
     2006                        }
     2007                }
     2008
     2009                // No matches.
     2010                return false;
     2011        }
     2012
     2013        /**
    19412014         * Constructor - Calls init(), which runs setup.
    19422015         *
    19432016         * @since 1.5.0
  • src/wp-includes/class-wp.php

     
    6565        public $request;
    6666
    6767        /**
    68          * Rewrite rule the request matched.
     68         * Rewrite rule pattern the request matched.
    6969         *
    7070         * @since 2.0.0
    7171         * @access public
     
    7474        public $matched_rule;
    7575
    7676        /**
     77         * Rewrite rule object the request matched.
     78         *
     79         * @access public
     80         * @var WP_Rewrite_RuleInterface
     81         */
     82        public $matched_rule_object;
     83
     84        /**
    7785         * Rewrite query the request matched.
    7886         *
    7987         * @since 2.0.0
     
    92100        public $did_permalink = false;
    93101
    94102        /**
     103         * Should we perform the main query?
     104         *
     105         * @since 4.6.0
     106         * @access public
     107         * @var bool
     108         */
     109        public $perform_main_query = true;
     110
     111        /**
    95112         * Add name to list of public query variables.
    96113         *
    97114         * @since 2.1.0
     
    212229                        $requested_file = $req_uri;
    213230
    214231                        $this->request = $requested_path;
     232                        $rewrite_match = $wp_rewrite->get_rewrite_rule_for_request( $requested_path, $requested_file );
    215233
    216                         // Look for matches.
    217                         $request_match = $requested_path;
    218                         if ( empty( $request_match ) ) {
    219                                 // An empty request could only match against ^$ regex
    220                                 if ( isset( $rewrite['$'] ) ) {
    221                                         $this->matched_rule = '$';
    222                                         $query = $rewrite['$'];
    223                                         $matches = array('');
    224                                 }
    225                         } else {
    226                                 foreach ( (array) $rewrite as $match => $query ) {
    227                                         // If the requested file is the anchor of the match, prepend it to the path info.
    228                                         if ( ! empty($requested_file) && strpos($match, $requested_file) === 0 && $requested_file != $requested_path )
    229                                                 $request_match = $requested_file . '/' . $requested_path;
     234                        if ( $rewrite_match ) {
     235                                $this->matched_rule = $rewrite_match[0];
     236                                $this->matched_rule_object = $rewrite_match[1];
     237                                $matches = $rewrite_match[2];
    230238
    231                                         if ( preg_match("#^$match#", $request_match, $matches) ||
    232                                                 preg_match("#^$match#", urldecode($request_match), $matches) ) {
     239                                // Substitute the substring matches into the query.
     240                                $query = $this->matched_rule_object->get_query_vars( $matches );
    233241
    234                                                 if ( $wp_rewrite->use_verbose_page_rules && preg_match( '/pagename=\$matches\[([0-9]+)\]/', $query, $varmatch ) ) {
    235                                                         // This is a verbose page match, let's check to be sure about it.
    236                                                         $page = get_page_by_path( $matches[ $varmatch[1] ] );
    237                                                         if ( ! $page ) {
    238                                                                 continue;
    239                                                         }
     242                                if ( is_array( $query ) ) {
     243                                        $perma_query_vars = $query;
    240244
    241                                                         $post_status_obj = get_post_status_object( $page->post_status );
    242                                                         if ( ! $post_status_obj->public && ! $post_status_obj->protected
    243                                                                 && ! $post_status_obj->private && $post_status_obj->exclude_from_search ) {
    244                                                                 continue;
    245                                                         }
    246                                                 }
    247 
    248                                                 // Got a match.
    249                                                 $this->matched_rule = $match;
    250                                                 break;
    251                                         }
     245                                        // For backwards compatibility, store as a string.
     246                                        $this->matched_query = http_build_query( $query, '', '&' );
     247                                } else {
     248                                        // Skip the main query.
     249                                        $this->perform_main_query = false;
     250                                        $this->matched_query = '';
    252251                                }
    253                         }
    254252
    255                         if ( isset( $this->matched_rule ) ) {
    256                                 // Trim the query of everything up to the '?'.
    257                                 $query = preg_replace("!^.+\?!", '', $query);
    258 
    259                                 // Substitute the substring matches into the query.
    260                                 $query = addslashes(WP_MatchesMapRegex::apply($query, $matches));
    261 
    262                                 $this->matched_query = $query;
    263 
    264                                 // Parse the query.
    265                                 parse_str($query, $perma_query_vars);
    266 
    267253                                // If we're processing a 404 request, clear the error var since we found something.
    268254                                if ( '404' == $error )
    269255                                        unset( $error, $_GET['error'] );
     
    606592        public function query_posts() {
    607593                global $wp_the_query;
    608594                $this->build_query_string();
    609                 $wp_the_query->query($this->query_vars);
     595                $wp_the_query->query( $this->query_vars );
    610596        }
    611597
    612598        /**
     
    724710                $this->init();
    725711                $this->parse_request($query_args);
    726712                $this->send_headers();
    727                 $this->query_posts();
    728                 $this->handle_404();
    729                 $this->register_globals();
    730713
    731714                /**
     715                 * Filter whether the main query should be run.
     716                 *
     717                 * Pages that don't require the main query should return `null` from a
     718                 * WP_Rewrite_RuleInterface object, or filter this value to false.
     719                 *
     720                 * @since 4.6.0
     721                 *
     722                 * @param bool $perform_query True to run the main query, false to skip.
     723                 * @param string $matched_rule Regular expression used to match the current request.
     724                 * @param WP_Rewrite_RuleInterface $matched_rule_object Rule object handling the current request.
     725                 */
     726                $peform_query = apply_filters( 'perform_main_query', $this->perform_main_query, $this->matched_rule, $this->matched_rule_object );
     727                if ( $peform_query ) {
     728                        $this->query_posts();
     729                        $this->handle_404();
     730                        $this->register_globals();
     731                }
     732
     733                /**
    732734                 * Fires once the WordPress environment has been set up.
    733735                 *
    734736                 * @since 2.1.0
  • src/wp-settings.php

     
    172172require( ABSPATH . WPINC . '/comment-template.php' );
    173173require( ABSPATH . WPINC . '/rewrite.php' );
    174174require( ABSPATH . WPINC . '/class-wp-rewrite.php' );
     175require( ABSPATH . WPINC . '/class-wp-rewrite-ruleinterface.php' );
     176require( ABSPATH . WPINC . '/class-wp-rewrite-rule.php' );
    175177require( ABSPATH . WPINC . '/feed.php' );
    176178require( ABSPATH . WPINC . '/bookmark.php' );
    177179require( ABSPATH . WPINC . '/bookmark-template.php' );