WordPress.org

Make WordPress Core

Ticket #48223: 48223-wp-refactor.patch

File 48223-wp-refactor.patch, 37.4 KB (added by apedog, 7 months ago)
  • new file wp-includes/class-wp-request-environment.php

    ---
     wp-includes/class-wp-request-environment.php | 649 +++++++++++++++++++++++++++
     wp-includes/class-wp.php                     | 474 ++-----------------
     wp-settings.php                              |   1 +
     3 files changed, 690 insertions(+), 434 deletions(-)
     create mode 100644 wp-includes/class-wp-request-environment.php
    
    diff --git a/wp-includes/class-wp-request-environment.php b/wp-includes/class-wp-request-environment.php
    new file mode 100644
    index 0000000000..0d92289b22
    - +  
     1<?php
     2/**
     3 * WordPress Request Environment.
     4 *
     5 * @package WordPress
     6 * @since x.x.x
     7 */
     8class WP_Request_Environment {
     9        /**
     10         * Public query variables.
     11         *
     12         * Long list of public query variables.
     13         *
     14         * @since 2.0.0
     15         * @var string[]
     16         */
     17        public $public_query_vars = array( 'm', 'p', 'posts', 'w', 'cat', 'withcomments', 'withoutcomments', 's', 'search', 'exact', 'sentence', 'calendar', 'page', 'paged', 'more', 'tb', 'pb', 'author', 'order', 'orderby', 'year', 'monthnum', 'day', 'hour', 'minute', 'second', 'name', 'category_name', 'tag', 'feed', 'author_name', 'pagename', 'page_id', 'error', 'attachment', 'attachment_id', 'subpost', 'subpost_id', 'preview', 'robots', 'favicon', 'taxonomy', 'term', 'cpage', 'post_type', 'embed' );
     18
     19        /**
     20         * Private query variables.
     21         *
     22         * Long list of private query variables.
     23         *
     24         * @since 2.0.0
     25         * @var string[]
     26         */
     27        public $private_query_vars = array( 'offset', 'posts_per_page', 'posts_per_archive_page', 'showposts', 'nopaging', 'post_type', 'post_status', 'category__in', 'category__not_in', 'category__and', 'tag__in', 'tag__not_in', 'tag__and', 'tag_slug__in', 'tag_slug__and', 'tag_id', 'post_mime_type', 'perm', 'comments_per_page', 'post__in', 'post__not_in', 'post_parent', 'post_parent__in', 'post_parent__not_in', 'title', 'fields' );
     28
     29        /**
     30         * Extra query variables set by the user.
     31         *
     32         * @since 2.1.0
     33         * @var array
     34         */
     35        public $extra_query_vars = array();
     36
     37        /**
     38         * Query variables for setting up the WordPress Query Loop.
     39         *
     40         * @since 2.0.0
     41         * @var array
     42         */
     43        public $query_vars;
     44
     45        /**
     46         * String parsed to set the query variables.
     47         *
     48         * @since 2.0.0
     49         * @var string
     50         */
     51        public $query_string;
     52
     53        /**
     54         * The request path, e.g. 2015/05/06.
     55         *
     56         * @since 2.0.0
     57         * @var string
     58         */
     59        public $request;
     60
     61        /**
     62         * The server environment - either a copy of $_SERVER or virtual
     63         *
     64         * @since x.x.x
     65         * @var array
     66         */
     67        public $server;
     68
     69        /**
     70         * The GET request - either a copy of $_GET or virtual
     71         *
     72         * @since x.x.x
     73         * @var array
     74         */
     75        public $get;
     76
     77        /**
     78         * The POST request - either a copy of $_POST or virtual
     79         *
     80         * @since x.x.x
     81         * @var array
     82         */
     83        public $post;
     84
     85        /**
     86         * Whether we want to match all rules.
     87         *
     88         * @since x.x.x
     89         * @var boolean
     90         */
     91        public $parse_multiple_rules;
     92
     93        /**
     94         * Rewrite rule the request matched.
     95         *
     96         * @since x.x.x
     97         * @var array
     98         */
     99        public $all_matched_rules = array();
     100
     101        /**
     102         * Rewrite rule the request matched.
     103         *
     104         * @since 2.0.0
     105         * @var string
     106         */
     107        public $matched_rule;
     108
     109        /**
     110         * Rewrite query the request matched.
     111         *
     112         * @since 2.0.0
     113         * @var string
     114         */
     115        public $matched_query;
     116
     117        /**
     118         * Whether already did the permalink.
     119         *
     120         * @since 2.0.0
     121         * @var bool
     122         */
     123        public $did_permalink = false;
     124
     125        /**
     126         * Internal (private?) The index of rule we're matching (@see $this->all_matched_rules).
     127         *
     128         * @since x.x.x
     129         * @var int
     130         */
     131        public $current_rule;
     132
     133        /**
     134         * Internal (private?) Whether we believe request should result in 404 error.
     135         *
     136         * @since x.x.x
     137         * @var bool
     138         */
     139        public $error;
     140
     141        /**
     142         * Internal (private?) Query vars extracted from permalink rewrite rule matching
     143         *
     144         * @since x.x.x
     145         * @var bool
     146         */
     147        public $perma_query_vars;
     148
     149        /**
     150         * Add name to list of public query variables.
     151         *
     152         * @since 2.1.0
     153         *
     154         * @param string $qv Query variable name.
     155         */
     156        public function add_query_var( $qv ) {
     157                if ( ! in_array( $qv, $this->public_query_vars ) ) {
     158                        $this->public_query_vars[] = $qv;
     159                }
     160        }
     161
     162        /**
     163         * Removes a query variable from a list of public query variables.
     164         *
     165         * @since 4.5.0
     166         *
     167         * @param string $name Query variable name.
     168         */
     169        public function remove_query_var( $name ) {
     170                $this->public_query_vars = array_diff( $this->public_query_vars, array( $name ) );
     171        }
     172
     173        /**
     174         * Set the value of a query variable.
     175         *
     176         * @since 2.3.0
     177         *
     178         * @param string $key Query variable name.
     179         * @param mixed $value Query variable value.
     180         */
     181        public function set_query_var( $key, $value ) {
     182                $this->query_vars[ $key ] = $value;
     183        }
     184
     185        /**
     186         * Setup Request Environment
     187         *
     188         * When extending class to write virtual environment - override this method
     189         *
     190         * @since x.x.x
     191         */
     192        public function setup_request_environment( $server=[], $get=[], $post=[], $wp_query=null, $wp_rewrite=null ){
     193               
     194                $this->server     = $server;
     195                $this->get        = $get;
     196                $this->post       = $post;
     197                $this->wp_query   = $wp_query;
     198                $this->wp_rewrite = $wp_rewrite;
     199
     200        }
     201
     202
     203        /**
     204         * Parse request to find correct WordPress query.
     205         *
     206         * Sets up the query variables based on the request. There are also many
     207         * filters and actions that can be used to further manipulate the result.
     208         *
     209         * @since 2.0.0
     210         *
     211         * @global WP_Rewrite $wp_rewrite WordPress rewrite component.
     212         *
     213         * @param array|string $extra_query_vars Set the extra query variables.
     214         */
     215        public function parse_request( $extra_query_vars = '' ) {
     216
     217                /**
     218                 * Filters whether to parse the request.
     219                 *
     220                 * @since 3.5.0
     221                 *
     222                 * @param bool         $bool             Whether or not to parse the request. Default true.
     223                 * @param WP           $this             Current WordPress environment instance.
     224                 * @param array|string $extra_query_vars Extra passed query variables.
     225                 */
     226                if ( ! apply_filters( 'do_parse_request', true, $this, $extra_query_vars ) ) {
     227                        return;
     228                }
     229
     230                $this->_match_rewrite_rules();
     231                $this->_match_single_rule();
     232                $this->_parse_request( $extra_query_vars );
     233        }
     234
     235
     236        /**
     237         * Match Rewrite Rules
     238         *
     239         * Matches request against all rewrite rules.
     240         * Sets current_rule index to 0
     241         *
     242         * @internal Do not use this directly. Use $this->parse_request().
     243         *
     244         * @since x.x.x
     245         */
     246        public function _match_rewrite_rules(){
     247               
     248                $rewrite = $this->wp_rewrite->wp_rewrite_rules();
     249
     250                if ( empty( $rewrite ) ) {
     251                        return;
     252                }
     253
     254                $home_path       = trim( parse_url( home_url(), PHP_URL_PATH ), '/' );
     255                $home_path_regex = sprintf( '|^%s|i', preg_quote( $home_path, '|' ) );
     256
     257                $pathinfo        = isset( $this->server['PATH_INFO'] ) ? $this->server['PATH_INFO'] : '';
     258                $pathinfo        = reset( explode( '?', $pathinfo ) );
     259                $pathinfo        = str_replace( '%', '%25', $pathinfo );
     260                $pathinfo        = trim( $pathinfo, '/' );
     261                $pathinfo        = preg_replace( $home_path_regex, '', $pathinfo );
     262                $pathinfo        = trim( $pathinfo, '/' );
     263
     264                $req_uri         = reset( explode( '?', $this->server['REQUEST_URI'] ) );
     265                $req_uri         = str_replace( $pathinfo, '', $req_uri );
     266                $req_uri         = trim( $req_uri, '/' );
     267                $req_uri         = preg_replace( $home_path_regex, '', $req_uri );
     268                $req_uri         = trim( $req_uri, '/' );
     269
     270                $self            = $this->server['PHP_SELF'];
     271                $self            = trim( $self, '/' );
     272                $self            = preg_replace( $home_path_regex, '', $self );
     273                $self            = trim( $self, '/' );
     274
     275               
     276                // The requested permalink is in $pathinfo for path info requests and
     277                // $req_uri for other requests.
     278                if ( ! empty( $pathinfo ) && ! preg_match( '|^.*' . $this->wp_rewrite->index . '$|', $pathinfo ) ) {
     279                        $this->request = $pathinfo;
     280                } else {
     281                        // If the request uri is the index, blank it out so that we don't try to match it against a rule.
     282                        if ( $req_uri == $this->wp_rewrite->index ) {
     283                                $req_uri = '';
     284                        }
     285                        $this->request = $req_uri;
     286                }
     287                $this->requested_file = $req_uri;
     288                $this->self = $self;
     289
     290                // Look for matches.
     291                $request_match = $this->request;
     292                if ( empty( $request_match ) ) {
     293                        // An empty request could only match against ^$ regex.
     294                        if ( isset( $rewrite['$'] ) ) {
     295                                $this->all_matched_rules[] = array(
     296                                        'rule'    => '$',
     297                                        'query'   => $rewrite['$'],
     298                                        'matches' => array( '' ),
     299                                );
     300                        }
     301                } else {
     302                        foreach ( (array) $rewrite as $match => $query ) {
     303                                // If the requested file is the anchor of the match, prepend it to the path info.
     304                                if ( ! empty( $this->requested_file ) && strpos( $match, $this->requested_file ) === 0 && $this->requested_file != $this->request ) {
     305                                        $request_match = $this->requested_file . '/' . $this->request;
     306                                }
     307
     308                                if ( preg_match( "#^$match#", $request_match, $matches ) ||
     309                                        preg_match( "#^$match#", urldecode( $request_match ), $matches ) ) {
     310
     311                                        if ( $this->wp_rewrite->use_verbose_page_rules && preg_match( '/pagename=\$matches\[([0-9]+)\]/', $query, $varmatch ) ) {
     312                                                // This is a verbose page match, let's check to be sure about it.
     313                                                $page = get_page_by_path( $matches[ $varmatch[1] ] );
     314                                                if ( ! $page ) {
     315                                                        continue;
     316                                                }
     317
     318                                                $post_status_obj = get_post_status_object( $page->post_status );
     319                                                if ( ! $post_status_obj->public && ! $post_status_obj->protected
     320                                                        && ! $post_status_obj->private && $post_status_obj->exclude_from_search ) {
     321                                                        continue;
     322                                                }
     323                                        }
     324
     325                                        // Got a match.
     326                                        $this->all_matched_rules[] = array(
     327                                                'rule'    => $match,
     328                                                'query'   => $query,
     329                                                'matches' => $matches,
     330                                        );
     331                                }
     332                        }
     333                }
     334
     335                $this->current_rule = 0; // set first matched rule index
     336        }
     337
     338        /**
     339         * match_single_rule
     340         *
     341         * @internal Do not use this directly. Use $this->parse_request().
     342         *
     343         * @since x.x.x
     344         */
     345        public function _match_single_rule(){
     346                // we set matched rule now
     347                if ( ! empty ($this->all_matched_rules ) ){
     348                        $current_match = $this->all_matched_rules[$this->current_rule];
     349                        $this->matched_rule = $current_match['rule'];
     350                        $query = $current_match['query'];
     351                        $matches = $current_match['matches'];
     352                }
     353
     354                // If we match a rewrite rule, this will be cleared.
     355                $this->error         = '404';
     356                $this->did_permalink = true;
     357
     358
     359                if ( isset( $this->matched_rule ) ) {
     360                        // Trim the query of everything up to the '?'.
     361                        $query = preg_replace( '!^.+\?!', '', $query );
     362
     363                        // Substitute the substring matches into the query.
     364                        $query = addslashes( WP_MatchesMapRegex::apply( $query, $matches ) );
     365
     366                        $this->matched_query = $query;
     367                       
     368                        // Parse the query.
     369                        parse_str( $query, $this->perma_query_vars );
     370                        // If we're processing a 404 request, clear the error var since we found something.
     371                        if ( '404' == $this->error ) {
     372                                $this->error = null;
     373                        }
     374                }
     375
     376                // If req_uri is empty or if it is a request for ourself, unset error.
     377                if ( empty( $this->request ) || $this->requested_file == $this->self || strpos( $this->server['PHP_SELF'], 'wp-admin/' ) !== false ) {
     378                        $this->error = null;
     379
     380                        if ( isset( $this->perma_query_vars ) && strpos( $this->server['PHP_SELF'], 'wp-admin/' ) !== false ) {
     381                                unset( $this->perma_query_vars );
     382                        }
     383
     384                        $this->did_permalink = false;
     385                }
     386        }
     387
     388
     389        /**
     390         * Does the actual request parsing after rule was matched and query vars set
     391         *
     392         * @internal Do not use this directly. Use $this->parse_request().
     393         *
     394         * @since x.x.x
     395         */
     396        public function _parse_request( $extra_query_vars = '' ) {
     397
     398                $this->query_vars = array();
     399
     400                /**
     401                 * Filters the query variables whitelist before processing.
     402                 *
     403                 * Allows (publicly allowed) query vars to be added, removed, or changed prior
     404                 * to executing the query. Needed to allow custom rewrite rules using your own arguments
     405                 * to work, or any other custom query variables you want to be publicly available.
     406                 *
     407                 * @since 1.5.0
     408                 *
     409                 * @param string[] $public_query_vars The array of whitelisted query variable names.
     410                 */
     411                $this->public_query_vars = apply_filters( 'query_vars', $this->public_query_vars );
     412
     413                $post_type_query_vars = array();
     414
     415                if ( is_array( $extra_query_vars ) ) {
     416                        $this->extra_query_vars = & $extra_query_vars;
     417                } elseif ( ! empty( $extra_query_vars ) ) {
     418                        parse_str( $extra_query_vars, $this->extra_query_vars );
     419                }
     420
     421                foreach ( get_post_types( array(), 'objects' ) as $post_type => $t ) {
     422                        if ( is_post_type_viewable( $t ) && $t->query_var ) {
     423                                $post_type_query_vars[ $t->query_var ] = $post_type;
     424                        }
     425                }
     426                foreach ( $this->public_query_vars as $wpvar ) {
     427                        if ( isset( $this->extra_query_vars[ $wpvar ] ) ) {
     428                                $this->query_vars[ $wpvar ] = $this->extra_query_vars[ $wpvar ];
     429                        } elseif ( isset( $this->get[ $wpvar ] ) && isset( $this->post[ $wpvar ] ) && $this->get[ $wpvar ] !== $this->post[ $wpvar ] ) {
     430                                wp_die( __( 'A variable mismatch has been detected.' ), __( 'Sorry, you are not allowed to view this item.' ), 400 );
     431                        } elseif ( isset( $this->post[ $wpvar ] ) ) {
     432                                $this->query_vars[ $wpvar ] = $this->post[ $wpvar ];
     433                        } elseif ( isset( $this->get[ $wpvar ] ) ) {
     434                                // if we've cleared error - skip
     435                                if ( 'error' == $wpvar && null == $this->error ){
     436                                        continue;
     437                                }
     438                                $this->query_vars[ $wpvar ] = $this->get[ $wpvar ];
     439                        } elseif ( isset( $this->perma_query_vars[ $wpvar ] ) ) {
     440                                $this->query_vars[ $wpvar ] = $this->perma_query_vars[ $wpvar ];
     441                        }
     442
     443                        if ( ! empty( $this->query_vars[ $wpvar ] ) ) {
     444                                if ( ! is_array( $this->query_vars[ $wpvar ] ) ) {
     445                                        $this->query_vars[ $wpvar ] = (string) $this->query_vars[ $wpvar ];
     446                                } else {
     447                                        foreach ( $this->query_vars[ $wpvar ] as $vkey => $v ) {
     448                                                if ( is_scalar( $v ) ) {
     449                                                        $this->query_vars[ $wpvar ][ $vkey ] = (string) $v;
     450                                                }
     451                                        }
     452                                }
     453
     454                                if ( isset( $post_type_query_vars[ $wpvar ] ) ) {
     455                                        $this->query_vars['post_type'] = $post_type_query_vars[ $wpvar ];
     456                                        $this->query_vars['name']      = $this->query_vars[ $wpvar ];
     457                                }
     458                        }
     459                }
     460
     461                // Convert urldecoded spaces back into '+'.
     462                foreach ( get_taxonomies( array(), 'objects' ) as $taxonomy => $t ) {
     463                        if ( $t->query_var && isset( $this->query_vars[ $t->query_var ] ) ) {
     464                                $this->query_vars[ $t->query_var ] = str_replace( ' ', '+', $this->query_vars[ $t->query_var ] );
     465                        }
     466                }
     467
     468                // Don't allow non-publicly queryable taxonomies to be queried from the front end.
     469                if ( ! is_admin() ) {
     470                        foreach ( get_taxonomies( array( 'publicly_queryable' => false ), 'objects' ) as $taxonomy => $t ) {
     471                                /*
     472                                 * Disallow when set to the 'taxonomy' query var.
     473                                 * Non-publicly queryable taxonomies cannot register custom query vars. See register_taxonomy().
     474                                 */
     475                                if ( isset( $this->query_vars['taxonomy'] ) && $taxonomy === $this->query_vars['taxonomy'] ) {
     476                                        unset( $this->query_vars['taxonomy'], $this->query_vars['term'] );
     477                                }
     478                        }
     479                }
     480
     481                // Limit publicly queried post_types to those that are 'publicly_queryable'.
     482                if ( isset( $this->query_vars['post_type'] ) ) {
     483                        $queryable_post_types = get_post_types( array( 'publicly_queryable' => true ) );
     484                        if ( ! is_array( $this->query_vars['post_type'] ) ) {
     485                                if ( ! in_array( $this->query_vars['post_type'], $queryable_post_types ) ) {
     486                                        unset( $this->query_vars['post_type'] );
     487                                }
     488                        } else {
     489                                $this->query_vars['post_type'] = array_intersect( $this->query_vars['post_type'], $queryable_post_types );
     490                        }
     491                }
     492
     493                // Resolve conflicts between posts with numeric slugs and date archive queries.
     494                $this->query_vars = wp_resolve_numeric_slug_conflicts( $this->query_vars );
     495
     496                foreach ( (array) $this->private_query_vars as $var ) {
     497                        if ( isset( $this->extra_query_vars[ $var ] ) ) {
     498                                $this->query_vars[ $var ] = $this->extra_query_vars[ $var ];
     499                        }
     500                }
     501
     502                if ( ! empty( $this->error ) ) {
     503                        $this->query_vars['error'] = $this->error;
     504                }
     505
     506                /**
     507                 * Filters the array of parsed query variables.
     508                 *
     509                 * @since 2.1.0
     510                 *
     511                 * @param array $query_vars The array of requested query variables.
     512                 */
     513                $this->query_vars = apply_filters( 'request', $this->query_vars );
     514
     515                /**
     516                 * Fires once all query variables for the current request have been parsed.
     517                 *
     518                 * @since 2.1.0
     519                 *
     520                 * @param WP $this Current WordPress environment instance (passed by reference).
     521                 */
     522                do_action_ref_array( 'parse_request', array( &$this ) );
     523        }
     524
     525
     526        /**
     527         * Reset WP_Query object
     528         * Used on _reparse_request()
     529         *
     530         * @since x.x.x
     531         */
     532        public function _reset_query(){
     533                $this->wp_query = new WP_Query();
     534        }
     535
     536
     537        /**
     538         * Reparse request
     539         *
     540         * If we're attempting multiple rule matching we need to re-parse query
     541         * Advances current_rule index
     542         * Sets up a new WP_Query instance.
     543         * Parses request _AND_ queries posts.
     544         *
     545         * @internal Do not use this directly. Use $this->main().
     546         *
     547         * @since x.x.x
     548         */
     549        public function _reparse_request(){
     550
     551                // if our query returned non-empty (200)
     552                // or if we've no more rules to match (404) - we return early
     553                if ( $this->wp_query->post_count != 0 || $this->current_rule >= count( $this->all_matched_rules )){
     554                        return;
     555                }
     556
     557                // advance counter and create new query
     558                $this->current_rule ++;
     559                $this->_reset_query();
     560
     561                $this->_match_single_rule();
     562                $this->_parse_request(); // no need to pass extra query args - they're already in $this->extra_query_vars
     563                $this->query_posts();
     564
     565                // recursive call
     566                $this->_reparse_request();
     567        }
     568
     569        /**
     570         * Sets the query string property based off of the query variable property.
     571         *
     572         * The {@see 'query_string'} filter is deprecated, but still works. Plugins should
     573         * use the {@see 'request'} filter instead.
     574         *
     575         * @since 2.0.0
     576         */
     577        public function build_query_string() {
     578                $this->query_string = '';
     579                foreach ( (array) array_keys( $this->query_vars ) as $wpvar ) {
     580                        if ( '' != $this->query_vars[ $wpvar ] ) {
     581                                $this->query_string .= ( strlen( $this->query_string ) < 1 ) ? '' : '&';
     582                                if ( ! is_scalar( $this->query_vars[ $wpvar ] ) ) { // Discard non-scalars.
     583                                        continue;
     584                                }
     585                                $this->query_string .= $wpvar . '=' . rawurlencode( $this->query_vars[ $wpvar ] );
     586                        }
     587                }
     588
     589                if ( has_filter( 'query_string' ) ) {  // Don't bother filtering and parsing if no plugins are hooked in.
     590                        /**
     591                         * Filters the query string before parsing.
     592                         *
     593                         * @since 1.5.0
     594                         * @deprecated 2.1.0 Use {@see 'query_vars'} or {@see 'request'} filters instead.
     595                         *
     596                         * @param string $query_string The query string to modify.
     597                         */
     598                        $this->query_string = apply_filters_deprecated(
     599                                'query_string',
     600                                array( $this->query_string ),
     601                                '2.1.0',
     602                                'query_vars, request'
     603                        );
     604                        parse_str( $this->query_string, $this->query_vars );
     605                }
     606        }
     607
     608        /**
     609         * Set up the Loop based on the query variables.
     610         *
     611         * @since 2.0.0
     612         *
     613         * @global WP_Query $wp_the_query WordPress Query object.
     614         */
     615        public function query_posts() {
     616                $this->build_query_string();
     617                $this->wp_query->query( $this->query_vars );
     618        }
     619
     620        /**
     621         * Sets up all of the variables required by the WordPress environment.
     622         *
     623         * The action {@see 'wp'} has one parameter that references the WP object. It
     624         * allows for accessing the properties and methods to further manipulate the
     625         * object.
     626         *
     627         * @since 2.0.0
     628         *
     629         * @param string|array $query_args Passed to parse_request().
     630         */
     631        public function main( $query_args = '' ) {
     632
     633                /**
     634                 * Filters wether to parse multiple rules if first match results in 404
     635                 * Default: false - Only match the first rule.
     636                 *
     637                 * @since x.x.x
     638                 */
     639                $this->parse_multiple_rules = apply_filters( 'parse_multiple_rules', false );
     640
     641                $this->parse_request( $query_args );
     642                $this->query_posts();
     643
     644                if ( $this->parse_multiple_rules ){
     645                        $this->_reparse_request();
     646                }
     647
     648        }
     649}
     650 No newline at end of file
  • wp-includes/class-wp.php

    diff --git a/wp-includes/class-wp.php b/wp-includes/class-wp.php
    index ba1f15d033..a3c1123835 100644
    a b  
    55 * @package WordPress
    66 * @since 2.0.0
    77 */
    8 class WP {
    9         /**
    10          * Public query variables.
    11          *
    12          * Long list of public query variables.
    13          *
    14          * @since 2.0.0
    15          * @var string[]
    16          */
    17         public $public_query_vars = array( 'm', 'p', 'posts', 'w', 'cat', 'withcomments', 'withoutcomments', 's', 'search', 'exact', 'sentence', 'calendar', 'page', 'paged', 'more', 'tb', 'pb', 'author', 'order', 'orderby', 'year', 'monthnum', 'day', 'hour', 'minute', 'second', 'name', 'category_name', 'tag', 'feed', 'author_name', 'pagename', 'page_id', 'error', 'attachment', 'attachment_id', 'subpost', 'subpost_id', 'preview', 'robots', 'favicon', 'taxonomy', 'term', 'cpage', 'post_type', 'embed' );
    18 
    19         /**
    20          * Private query variables.
    21          *
    22          * Long list of private query variables.
    23          *
    24          * @since 2.0.0
    25          * @var string[]
    26          */
    27         public $private_query_vars = array( 'offset', 'posts_per_page', 'posts_per_archive_page', 'showposts', 'nopaging', 'post_type', 'post_status', 'category__in', 'category__not_in', 'category__and', 'tag__in', 'tag__not_in', 'tag__and', 'tag_slug__in', 'tag_slug__and', 'tag_id', 'post_mime_type', 'perm', 'comments_per_page', 'post__in', 'post__not_in', 'post_parent', 'post_parent__in', 'post_parent__not_in', 'title', 'fields' );
    28 
    29         /**
    30          * Extra query variables set by the user.
    31          *
    32          * @since 2.1.0
    33          * @var array
    34          */
    35         public $extra_query_vars = array();
    36 
    37         /**
    38          * Query variables for setting up the WordPress Query Loop.
    39          *
    40          * @since 2.0.0
    41          * @var array
    42          */
    43         public $query_vars;
    44 
    45         /**
    46          * String parsed to set the query variables.
    47          *
    48          * @since 2.0.0
    49          * @var string
    50          */
    51         public $query_string;
    52 
    53         /**
    54          * The request path, e.g. 2015/05/06.
    55          *
    56          * @since 2.0.0
    57          * @var string
    58          */
    59         public $request;
    60 
    61         /**
    62          * Rewrite rule the request matched.
    63          *
    64          * @since 2.0.0
    65          * @var string
    66          */
    67         public $matched_rule;
    68 
    69         /**
    70          * Rewrite query the request matched.
    71          *
    72          * @since 2.0.0
    73          * @var string
    74          */
    75         public $matched_query;
    76 
    77         /**
    78          * Whether already did the permalink.
    79          *
    80          * @since 2.0.0
    81          * @var bool
    82          */
    83         public $did_permalink = false;
    84 
    85         /**
    86          * Add name to list of public query variables.
    87          *
    88          * @since 2.1.0
    89          *
    90          * @param string $qv Query variable name.
    91          */
    92         public function add_query_var( $qv ) {
    93                 if ( ! in_array( $qv, $this->public_query_vars, true ) ) {
    94                         $this->public_query_vars[] = $qv;
    95                 }
    96         }
    97 
    98         /**
    99          * Removes a query variable from a list of public query variables.
    100          *
    101          * @since 4.5.0
    102          *
    103          * @param string $name Query variable name.
    104          */
    105         public function remove_query_var( $name ) {
    106                 $this->public_query_vars = array_diff( $this->public_query_vars, array( $name ) );
    107         }
    108 
    109         /**
    110          * Set the value of a query variable.
    111          *
    112          * @since 2.3.0
    113          *
    114          * @param string $key Query variable name.
    115          * @param mixed $value Query variable value.
    116          */
    117         public function set_query_var( $key, $value ) {
    118                 $this->query_vars[ $key ] = $value;
    119         }
    120 
    121         /**
    122          * Parse request to find correct WordPress query.
    123          *
    124          * Sets up the query variables based on the request. There are also many
    125          * filters and actions that can be used to further manipulate the result.
    126          *
    127          * @since 2.0.0
    128          *
    129          * @global WP_Rewrite $wp_rewrite WordPress rewrite component.
    130          *
    131          * @param array|string $extra_query_vars Set the extra query variables.
    132          */
    133         public function parse_request( $extra_query_vars = '' ) {
    134                 global $wp_rewrite;
    135 
    136                 /**
    137                  * Filters whether to parse the request.
    138                  *
    139                  * @since 3.5.0
    140                  *
    141                  * @param bool         $bool             Whether or not to parse the request. Default true.
    142                  * @param WP           $this             Current WordPress environment instance.
    143                  * @param array|string $extra_query_vars Extra passed query variables.
    144                  */
    145                 if ( ! apply_filters( 'do_parse_request', true, $this, $extra_query_vars ) ) {
    146                         return;
    147                 }
    148 
    149                 $this->query_vars     = array();
    150                 $post_type_query_vars = array();
    151 
    152                 if ( is_array( $extra_query_vars ) ) {
    153                         $this->extra_query_vars = & $extra_query_vars;
    154                 } elseif ( ! empty( $extra_query_vars ) ) {
    155                         parse_str( $extra_query_vars, $this->extra_query_vars );
    156                 }
    157                 // Process PATH_INFO, REQUEST_URI, and 404 for permalinks.
    158 
    159                 // Fetch the rewrite rules.
    160                 $rewrite = $wp_rewrite->wp_rewrite_rules();
    161 
    162                 if ( ! empty( $rewrite ) ) {
    163                         // If we match a rewrite rule, this will be cleared.
    164                         $error               = '404';
    165                         $this->did_permalink = true;
    166 
    167                         $pathinfo         = isset( $_SERVER['PATH_INFO'] ) ? $_SERVER['PATH_INFO'] : '';
    168                         list( $pathinfo ) = explode( '?', $pathinfo );
    169                         $pathinfo         = str_replace( '%', '%25', $pathinfo );
    170 
    171                         list( $req_uri ) = explode( '?', $_SERVER['REQUEST_URI'] );
    172                         $self            = $_SERVER['PHP_SELF'];
    173                         $home_path       = trim( parse_url( home_url(), PHP_URL_PATH ), '/' );
    174                         $home_path_regex = sprintf( '|^%s|i', preg_quote( $home_path, '|' ) );
    175 
    176                         /*
    177                          * Trim path info from the end and the leading home path from the front.
    178                          * For path info requests, this leaves us with the requesting filename, if any.
    179                          * For 404 requests, this leaves us with the requested permalink.
    180                          */
    181                         $req_uri  = str_replace( $pathinfo, '', $req_uri );
    182                         $req_uri  = trim( $req_uri, '/' );
    183                         $req_uri  = preg_replace( $home_path_regex, '', $req_uri );
    184                         $req_uri  = trim( $req_uri, '/' );
    185                         $pathinfo = trim( $pathinfo, '/' );
    186                         $pathinfo = preg_replace( $home_path_regex, '', $pathinfo );
    187                         $pathinfo = trim( $pathinfo, '/' );
    188                         $self     = trim( $self, '/' );
    189                         $self     = preg_replace( $home_path_regex, '', $self );
    190                         $self     = trim( $self, '/' );
    191 
    192                         // The requested permalink is in $pathinfo for path info requests and
    193                         // $req_uri for other requests.
    194                         if ( ! empty( $pathinfo ) && ! preg_match( '|^.*' . $wp_rewrite->index . '$|', $pathinfo ) ) {
    195                                 $requested_path = $pathinfo;
    196                         } else {
    197                                 // If the request uri is the index, blank it out so that we don't try to match it against a rule.
    198                                 if ( $req_uri == $wp_rewrite->index ) {
    199                                         $req_uri = '';
    200                                 }
    201                                 $requested_path = $req_uri;
    202                         }
    203                         $requested_file = $req_uri;
    204 
    205                         $this->request = $requested_path;
    206 
    207                         // Look for matches.
    208                         $request_match = $requested_path;
    209                         if ( empty( $request_match ) ) {
    210                                 // An empty request could only match against ^$ regex.
    211                                 if ( isset( $rewrite['$'] ) ) {
    212                                         $this->matched_rule = '$';
    213                                         $query              = $rewrite['$'];
    214                                         $matches            = array( '' );
    215                                 }
    216                         } else {
    217                                 foreach ( (array) $rewrite as $match => $query ) {
    218                                         // If the requested file is the anchor of the match, prepend it to the path info.
    219                                         if ( ! empty( $requested_file ) && strpos( $match, $requested_file ) === 0 && $requested_file != $requested_path ) {
    220                                                 $request_match = $requested_file . '/' . $requested_path;
    221                                         }
    222 
    223                                         if ( preg_match( "#^$match#", $request_match, $matches ) ||
    224                                                 preg_match( "#^$match#", urldecode( $request_match ), $matches ) ) {
    225 
    226                                                 if ( $wp_rewrite->use_verbose_page_rules && preg_match( '/pagename=\$matches\[([0-9]+)\]/', $query, $varmatch ) ) {
    227                                                         // This is a verbose page match, let's check to be sure about it.
    228                                                         $page = get_page_by_path( $matches[ $varmatch[1] ] );
    229                                                         if ( ! $page ) {
    230                                                                 continue;
    231                                                         }
    232 
    233                                                         $post_status_obj = get_post_status_object( $page->post_status );
    234                                                         if ( ! $post_status_obj->public && ! $post_status_obj->protected
    235                                                                 && ! $post_status_obj->private && $post_status_obj->exclude_from_search ) {
    236                                                                 continue;
    237                                                         }
    238                                                 }
    239 
    240                                                 // Got a match.
    241                                                 $this->matched_rule = $match;
    242                                                 break;
    243                                         }
    244                                 }
    245                         }
    246 
    247                         if ( isset( $this->matched_rule ) ) {
    248                                 // Trim the query of everything up to the '?'.
    249                                 $query = preg_replace( '!^.+\?!', '', $query );
    250 
    251                                 // Substitute the substring matches into the query.
    252                                 $query = addslashes( WP_MatchesMapRegex::apply( $query, $matches ) );
    253 
    254                                 $this->matched_query = $query;
    255 
    256                                 // Parse the query.
    257                                 parse_str( $query, $perma_query_vars );
    258 
    259                                 // If we're processing a 404 request, clear the error var since we found something.
    260                                 if ( '404' == $error ) {
    261                                         unset( $error, $_GET['error'] );
    262                                 }
    263                         }
    264 
    265                         // If req_uri is empty or if it is a request for ourself, unset error.
    266                         if ( empty( $requested_path ) || $requested_file == $self || strpos( $_SERVER['PHP_SELF'], 'wp-admin/' ) !== false ) {
    267                                 unset( $error, $_GET['error'] );
    268 
    269                                 if ( isset( $perma_query_vars ) && strpos( $_SERVER['PHP_SELF'], 'wp-admin/' ) !== false ) {
    270                                         unset( $perma_query_vars );
    271                                 }
    272 
    273                                 $this->did_permalink = false;
    274                         }
    275                 }
    276 
    277                 /**
    278                  * Filters the query variables whitelist before processing.
    279                  *
    280                  * Allows (publicly allowed) query vars to be added, removed, or changed prior
    281                  * to executing the query. Needed to allow custom rewrite rules using your own arguments
    282                  * to work, or any other custom query variables you want to be publicly available.
    283                  *
    284                  * @since 1.5.0
    285                  *
    286                  * @param string[] $public_query_vars The array of whitelisted query variable names.
    287                  */
    288                 $this->public_query_vars = apply_filters( 'query_vars', $this->public_query_vars );
    289 
    290                 foreach ( get_post_types( array(), 'objects' ) as $post_type => $t ) {
    291                         if ( is_post_type_viewable( $t ) && $t->query_var ) {
    292                                 $post_type_query_vars[ $t->query_var ] = $post_type;
    293                         }
    294                 }
    295 
    296                 foreach ( $this->public_query_vars as $wpvar ) {
    297                         if ( isset( $this->extra_query_vars[ $wpvar ] ) ) {
    298                                 $this->query_vars[ $wpvar ] = $this->extra_query_vars[ $wpvar ];
    299                         } elseif ( isset( $_GET[ $wpvar ] ) && isset( $_POST[ $wpvar ] ) && $_GET[ $wpvar ] !== $_POST[ $wpvar ] ) {
    300                                 wp_die( __( 'A variable mismatch has been detected.' ), __( 'Sorry, you are not allowed to view this item.' ), 400 );
    301                         } elseif ( isset( $_POST[ $wpvar ] ) ) {
    302                                 $this->query_vars[ $wpvar ] = $_POST[ $wpvar ];
    303                         } elseif ( isset( $_GET[ $wpvar ] ) ) {
    304                                 $this->query_vars[ $wpvar ] = $_GET[ $wpvar ];
    305                         } elseif ( isset( $perma_query_vars[ $wpvar ] ) ) {
    306                                 $this->query_vars[ $wpvar ] = $perma_query_vars[ $wpvar ];
    307                         }
    308 
    309                         if ( ! empty( $this->query_vars[ $wpvar ] ) ) {
    310                                 if ( ! is_array( $this->query_vars[ $wpvar ] ) ) {
    311                                         $this->query_vars[ $wpvar ] = (string) $this->query_vars[ $wpvar ];
    312                                 } else {
    313                                         foreach ( $this->query_vars[ $wpvar ] as $vkey => $v ) {
    314                                                 if ( is_scalar( $v ) ) {
    315                                                         $this->query_vars[ $wpvar ][ $vkey ] = (string) $v;
    316                                                 }
    317                                         }
    318                                 }
    319 
    320                                 if ( isset( $post_type_query_vars[ $wpvar ] ) ) {
    321                                         $this->query_vars['post_type'] = $post_type_query_vars[ $wpvar ];
    322                                         $this->query_vars['name']      = $this->query_vars[ $wpvar ];
    323                                 }
    324                         }
    325                 }
    326 
    327                 // Convert urldecoded spaces back into '+'.
    328                 foreach ( get_taxonomies( array(), 'objects' ) as $taxonomy => $t ) {
    329                         if ( $t->query_var && isset( $this->query_vars[ $t->query_var ] ) ) {
    330                                 $this->query_vars[ $t->query_var ] = str_replace( ' ', '+', $this->query_vars[ $t->query_var ] );
    331                         }
    332                 }
    333 
    334                 // Don't allow non-publicly queryable taxonomies to be queried from the front end.
    335                 if ( ! is_admin() ) {
    336                         foreach ( get_taxonomies( array( 'publicly_queryable' => false ), 'objects' ) as $taxonomy => $t ) {
    337                                 /*
    338                                  * Disallow when set to the 'taxonomy' query var.
    339                                  * Non-publicly queryable taxonomies cannot register custom query vars. See register_taxonomy().
    340                                  */
    341                                 if ( isset( $this->query_vars['taxonomy'] ) && $taxonomy === $this->query_vars['taxonomy'] ) {
    342                                         unset( $this->query_vars['taxonomy'], $this->query_vars['term'] );
    343                                 }
    344                         }
    345                 }
    346 
    347                 // Limit publicly queried post_types to those that are 'publicly_queryable'.
    348                 if ( isset( $this->query_vars['post_type'] ) ) {
    349                         $queryable_post_types = get_post_types( array( 'publicly_queryable' => true ) );
    350                         if ( ! is_array( $this->query_vars['post_type'] ) ) {
    351                                 if ( ! in_array( $this->query_vars['post_type'], $queryable_post_types, true ) ) {
    352                                         unset( $this->query_vars['post_type'] );
    353                                 }
    354                         } else {
    355                                 $this->query_vars['post_type'] = array_intersect( $this->query_vars['post_type'], $queryable_post_types );
    356                         }
    357                 }
    358 
    359                 // Resolve conflicts between posts with numeric slugs and date archive queries.
    360                 $this->query_vars = wp_resolve_numeric_slug_conflicts( $this->query_vars );
    361 
    362                 foreach ( (array) $this->private_query_vars as $var ) {
    363                         if ( isset( $this->extra_query_vars[ $var ] ) ) {
    364                                 $this->query_vars[ $var ] = $this->extra_query_vars[ $var ];
    365                         }
    366                 }
    367 
    368                 if ( isset( $error ) ) {
    369                         $this->query_vars['error'] = $error;
    370                 }
    371 
    372                 /**
    373                  * Filters the array of parsed query variables.
    374                  *
    375                  * @since 2.1.0
    376                  *
    377                  * @param array $query_vars The array of requested query variables.
    378                  */
    379                 $this->query_vars = apply_filters( 'request', $this->query_vars );
    380 
    381                 /**
    382                  * Fires once all query variables for the current request have been parsed.
    383                  *
    384                  * @since 2.1.0
    385                  *
    386                  * @param WP $this Current WordPress environment instance (passed by reference).
    387                  */
    388                 do_action_ref_array( 'parse_request', array( &$this ) );
    389         }
     8class WP extends WP_Request_Environment{
     9       
    39010
    39111        /**
    39212         * Sends additional HTTP headers for caching, content type, etc.
    class WP { 
    45474                        $headers['ETag']          = $wp_etag;
    45575
    45676                        // Support for conditional GET.
    457                         if ( isset( $_SERVER['HTTP_IF_NONE_MATCH'] ) ) {
    458                                 $client_etag = wp_unslash( $_SERVER['HTTP_IF_NONE_MATCH'] );
     77                        if ( isset( $this->server['HTTP_IF_NONE_MATCH'] ) ) {
     78                                $client_etag = wp_unslash( $this->server['HTTP_IF_NONE_MATCH'] );
    45979                        } else {
    46080                                $client_etag = false;
    46181                        }
    46282
    463                         $client_last_modified = empty( $_SERVER['HTTP_IF_MODIFIED_SINCE'] ) ? '' : trim( $_SERVER['HTTP_IF_MODIFIED_SINCE'] );
     83                        $client_last_modified = empty( $this->server['HTTP_IF_MODIFIED_SINCE'] ) ? '' : trim( $this->server['HTTP_IF_MODIFIED_SINCE'] );
    46484                        // If string is empty, return 0. If not, attempt to parse into a timestamp.
    46585                        $client_modified_timestamp = $client_last_modified ? strtotime( $client_last_modified ) : 0;
    46686
    class WP { 
    519139        }
    520140
    521141        /**
    522          * Sets the query string property based off of the query variable property.
    523          *
    524          * The {@see 'query_string'} filter is deprecated, but still works. Plugins should
    525          * use the {@see 'request'} filter instead.
    526          *
    527          * @since 2.0.0
     142         * Reset WP_Query object
     143         * Used on _reparse_request()
     144         * Reset global $wp_query if necessary
     145         *
     146         * note: some plugins use pre_handle_404 incorrectly.
     147         * They don't used passed $wp_query parameter. Instead they modify global $wp_query directly.
     148         * So class WP must update global $wp_query every time.
     149         *
     150         * @since x.x.x
    528151         */
    529         public function build_query_string() {
    530                 $this->query_string = '';
    531                 foreach ( (array) array_keys( $this->query_vars ) as $wpvar ) {
    532                         if ( '' != $this->query_vars[ $wpvar ] ) {
    533                                 $this->query_string .= ( strlen( $this->query_string ) < 1 ) ? '' : '&';
    534                                 if ( ! is_scalar( $this->query_vars[ $wpvar ] ) ) { // Discard non-scalars.
    535                                         continue;
    536                                 }
    537                                 $this->query_string .= $wpvar . '=' . rawurlencode( $this->query_vars[ $wpvar ] );
    538                         }
    539                 }
     152        public function _reset_query(){
     153                global $wp_query;
     154                global $wp_the_query;
     155
     156                parent::_reset_query();
    540157
    541                 if ( has_filter( 'query_string' ) ) {  // Don't bother filtering and parsing if no plugins are hooked in.
    542                         /**
    543                          * Filters the query string before parsing.
    544                          *
    545                          * @since 1.5.0
    546                          * @deprecated 2.1.0 Use {@see 'query_vars'} or {@see 'request'} filters instead.
    547                          *
    548                          * @param string $query_string The query string to modify.
    549                          */
    550                         $this->query_string = apply_filters_deprecated(
    551                                 'query_string',
    552                                 array( $this->query_string ),
    553                                 '2.1.0',
    554                                 'query_vars, request'
    555                         );
    556                         parse_str( $this->query_string, $this->query_vars );
     158                // if we've created new WP_Query object - let's insert it back into globals
     159                // The following condition will only execute if parse_multiple_rules == true and first matched rule has failed
     160                if ($wp_query !== $this->wp_query){
     161                        $wp_query = $this->wp_query;
     162                        $wp_the_query = $wp_query;
    557163                }
    558164        }
    559165
    class WP { 
    578184        public function register_globals() {
    579185                global $wp_query;
    580186
     187                // moved here from _parse_request()
     188                if ( null == $this->error ){
     189                        unset( $_GET['error'] );
     190                }
     191
    581192                // Extract updated query vars back into global namespace.
    582193                foreach ( (array) $wp_query->query_vars as $key => $value ) {
    583194                        $GLOBALS[ $key ] = $value;
    class WP { 
    607218                wp_get_current_user();
    608219        }
    609220
    610         /**
    611          * Set up the Loop based on the query variables.
    612          *
    613          * @since 2.0.0
    614          *
    615          * @global WP_Query $wp_the_query WordPress Query object.
    616          */
    617         public function query_posts() {
    618                 global $wp_the_query;
    619                 $this->build_query_string();
    620                 $wp_the_query->query( $this->query_vars );
    621         }
    622 
    623221        /**
    624222         * Set the Headers for 404, if nothing is found for requested URL.
    625223         *
    class WP { 
    737335         * @param string|array $query_args Passed to parse_request().
    738336         */
    739337        public function main( $query_args = '' ) {
     338                global $wp_the_query;
     339                global $wp_rewrite;
     340
    740341                $this->init();
    741                 $this->parse_request( $query_args );
    742                 $this->send_headers();
    743                 $this->query_posts();
     342
     343                $this->setup_request_environment( $_SERVER, $_GET, $_POST, $wp_the_query, $wp_rewrite );
     344
     345                parent::main();
     346
    744347                $this->handle_404();
     348
     349                $this->send_headers();
     350
    745351                $this->register_globals();
    746352
    747353                /**
  • wp-settings.php

    diff --git a/wp-settings.php b/wp-settings.php
    index 1a5f296733..125e095545 100644
    a b require ABSPATH . WPINC . '/meta.php'; 
    111111require ABSPATH . WPINC . '/functions.php';
    112112require ABSPATH . WPINC . '/class-wp-meta-query.php';
    113113require ABSPATH . WPINC . '/class-wp-matchesmapregex.php';
     114require ABSPATH . WPINC . '/class-wp-request-environment.php';
    114115require ABSPATH . WPINC . '/class-wp.php';
    115116require ABSPATH . WPINC . '/class-wp-error.php';
    116117require ABSPATH . WPINC . '/pomo/mo.php';