wp/wp-includes/class-wp.php
changeset 7 cf61fcea0001
parent 5 5e2f62d02dcd
child 9 177826044cd9
equal deleted inserted replaced
6:490d5cc509ed 7:cf61fcea0001
    10 	 * Public query variables.
    10 	 * Public query variables.
    11 	 *
    11 	 *
    12 	 * Long list of public query variables.
    12 	 * Long list of public query variables.
    13 	 *
    13 	 *
    14 	 * @since 2.0.0
    14 	 * @since 2.0.0
    15 	 * @access public
       
    16 	 * @var array
    15 	 * @var array
    17 	 */
    16 	 */
    18 	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', 'static', 'pagename', 'page_id', 'error', 'comments_popup', 'attachment', 'attachment_id', 'subpost', 'subpost_id', 'preview', 'robots', 'taxonomy', 'term', 'cpage', 'post_type');
    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', 'static', 'pagename', 'page_id', 'error', 'attachment', 'attachment_id', 'subpost', 'subpost_id', 'preview', 'robots', 'taxonomy', 'term', 'cpage', 'post_type', 'embed' );
    19 
    18 
    20 	/**
    19 	/**
    21 	 * Private query variables.
    20 	 * Private query variables.
    22 	 *
    21 	 *
    23 	 * Long list of private query variables.
    22 	 * Long list of private query variables.
    24 	 *
    23 	 *
    25 	 * @since 2.0.0
    24 	 * @since 2.0.0
    26 	 * @var array
    25 	 * @var array
    27 	 */
    26 	 */
    28 	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' );
    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' );
    29 
    28 
    30 	/**
    29 	/**
    31 	 * Extra query variables set by the user.
    30 	 * Extra query variables set by the user.
    32 	 *
    31 	 *
    33 	 * @since 2.1.0
    32 	 * @since 2.1.0
    50 	 * @var string
    49 	 * @var string
    51 	 */
    50 	 */
    52 	public $query_string;
    51 	public $query_string;
    53 
    52 
    54 	/**
    53 	/**
    55 	 * Permalink or requested URI.
    54 	 * The request path, e.g. 2015/05/06.
    56 	 *
    55 	 *
    57 	 * @since 2.0.0
    56 	 * @since 2.0.0
    58 	 * @var string
    57 	 * @var string
    59 	 */
    58 	 */
    60 	public $request;
    59 	public $request;
    94 		if ( !in_array($qv, $this->public_query_vars) )
    93 		if ( !in_array($qv, $this->public_query_vars) )
    95 			$this->public_query_vars[] = $qv;
    94 			$this->public_query_vars[] = $qv;
    96 	}
    95 	}
    97 
    96 
    98 	/**
    97 	/**
       
    98 	 * Removes a query variable from a list of public query variables.
       
    99 	 *
       
   100 	 * @since 4.5.0
       
   101 	 *
       
   102 	 * @param string $name Query variable name.
       
   103 	 */
       
   104 	public function remove_query_var( $name ) {
       
   105 		$this->public_query_vars = array_diff( $this->public_query_vars, array( $name ) );
       
   106 	}
       
   107 
       
   108 	/**
    99 	 * Set the value of a query variable.
   109 	 * Set the value of a query variable.
   100 	 *
   110 	 *
   101 	 * @since 2.3.0
   111 	 * @since 2.3.0
   102 	 *
   112 	 *
   103 	 * @param string $key Query variable name.
   113 	 * @param string $key Query variable name.
   113 	 * Sets up the query variables based on the request. There are also many
   123 	 * Sets up the query variables based on the request. There are also many
   114 	 * filters and actions that can be used to further manipulate the result.
   124 	 * filters and actions that can be used to further manipulate the result.
   115 	 *
   125 	 *
   116 	 * @since 2.0.0
   126 	 * @since 2.0.0
   117 	 *
   127 	 *
       
   128 	 * @global WP_Rewrite $wp_rewrite
       
   129 	 *
   118 	 * @param array|string $extra_query_vars Set the extra query variables.
   130 	 * @param array|string $extra_query_vars Set the extra query variables.
   119 	 */
   131 	 */
   120 	public function parse_request($extra_query_vars = '') {
   132 	public function parse_request($extra_query_vars = '') {
   121 		global $wp_rewrite;
   133 		global $wp_rewrite;
   122 
   134 
   123 		/**
   135 		/**
   124 		 * Filter whether to parse the request.
   136 		 * Filters whether to parse the request.
   125 		 *
   137 		 *
   126 		 * @since 3.5.0
   138 		 * @since 3.5.0
   127 		 *
   139 		 *
   128 		 * @param bool         $bool             Whether or not to parse the request. Default true.
   140 		 * @param bool         $bool             Whether or not to parse the request. Default true.
   129 		 * @param WP           $this             Current WordPress environment instance.
   141 		 * @param WP           $this             Current WordPress environment instance.
   155 			$pathinfo = str_replace( "%", "%25", $pathinfo );
   167 			$pathinfo = str_replace( "%", "%25", $pathinfo );
   156 
   168 
   157 			list( $req_uri ) = explode( '?', $_SERVER['REQUEST_URI'] );
   169 			list( $req_uri ) = explode( '?', $_SERVER['REQUEST_URI'] );
   158 			$self = $_SERVER['PHP_SELF'];
   170 			$self = $_SERVER['PHP_SELF'];
   159 			$home_path = trim( parse_url( home_url(), PHP_URL_PATH ), '/' );
   171 			$home_path = trim( parse_url( home_url(), PHP_URL_PATH ), '/' );
       
   172 			$home_path_regex = sprintf( '|^%s|i', preg_quote( $home_path, '|' ) );
   160 
   173 
   161 			// Trim path info from the end and the leading home path from the
   174 			// Trim path info from the end and the leading home path from the
   162 			// front. For path info requests, this leaves us with the requesting
   175 			// front. For path info requests, this leaves us with the requesting
   163 			// filename, if any. For 404 requests, this leaves us with the
   176 			// filename, if any. For 404 requests, this leaves us with the
   164 			// requested permalink.
   177 			// requested permalink.
   165 			$req_uri = str_replace($pathinfo, '', $req_uri);
   178 			$req_uri = str_replace($pathinfo, '', $req_uri);
   166 			$req_uri = trim($req_uri, '/');
   179 			$req_uri = trim($req_uri, '/');
   167 			$req_uri = preg_replace("|^$home_path|i", '', $req_uri);
   180 			$req_uri = preg_replace( $home_path_regex, '', $req_uri );
   168 			$req_uri = trim($req_uri, '/');
   181 			$req_uri = trim($req_uri, '/');
   169 			$pathinfo = trim($pathinfo, '/');
   182 			$pathinfo = trim($pathinfo, '/');
   170 			$pathinfo = preg_replace("|^$home_path|i", '', $pathinfo);
   183 			$pathinfo = preg_replace( $home_path_regex, '', $pathinfo );
   171 			$pathinfo = trim($pathinfo, '/');
   184 			$pathinfo = trim($pathinfo, '/');
   172 			$self = trim($self, '/');
   185 			$self = trim($self, '/');
   173 			$self = preg_replace("|^$home_path|i", '', $self);
   186 			$self = preg_replace( $home_path_regex, '', $self );
   174 			$self = trim($self, '/');
   187 			$self = trim($self, '/');
   175 
   188 
   176 			// The requested permalink is in $pathinfo for path info requests and
   189 			// The requested permalink is in $pathinfo for path info requests and
   177 			//  $req_uri for other requests.
   190 			//  $req_uri for other requests.
   178 			if ( ! empty($pathinfo) && !preg_match('|^.*' . $wp_rewrite->index . '$|', $pathinfo) ) {
   191 			if ( ! empty($pathinfo) && !preg_match('|^.*' . $wp_rewrite->index . '$|', $pathinfo) ) {
   179 				$request = $pathinfo;
   192 				$requested_path = $pathinfo;
   180 			} else {
   193 			} else {
   181 				// If the request uri is the index, blank it out so that we don't try to match it against a rule.
   194 				// If the request uri is the index, blank it out so that we don't try to match it against a rule.
   182 				if ( $req_uri == $wp_rewrite->index )
   195 				if ( $req_uri == $wp_rewrite->index )
   183 					$req_uri = '';
   196 					$req_uri = '';
   184 				$request = $req_uri;
   197 				$requested_path = $req_uri;
   185 			}
   198 			}
   186 
   199 			$requested_file = $req_uri;
   187 			$this->request = $request;
   200 
       
   201 			$this->request = $requested_path;
   188 
   202 
   189 			// Look for matches.
   203 			// Look for matches.
   190 			$request_match = $request;
   204 			$request_match = $requested_path;
   191 			if ( empty( $request_match ) ) {
   205 			if ( empty( $request_match ) ) {
   192 				// An empty request could only match against ^$ regex
   206 				// An empty request could only match against ^$ regex
   193 				if ( isset( $rewrite['$'] ) ) {
   207 				if ( isset( $rewrite['$'] ) ) {
   194 					$this->matched_rule = '$';
   208 					$this->matched_rule = '$';
   195 					$query = $rewrite['$'];
   209 					$query = $rewrite['$'];
   196 					$matches = array('');
   210 					$matches = array('');
   197 				}
   211 				}
   198 			} else {
   212 			} else {
   199 				foreach ( (array) $rewrite as $match => $query ) {
   213 				foreach ( (array) $rewrite as $match => $query ) {
   200 					// If the requesting file is the anchor of the match, prepend it to the path info.
   214 					// If the requested file is the anchor of the match, prepend it to the path info.
   201 					if ( ! empty($req_uri) && strpos($match, $req_uri) === 0 && $req_uri != $request )
   215 					if ( ! empty($requested_file) && strpos($match, $requested_file) === 0 && $requested_file != $requested_path )
   202 						$request_match = $req_uri . '/' . $request;
   216 						$request_match = $requested_file . '/' . $requested_path;
   203 
   217 
   204 					if ( preg_match("#^$match#", $request_match, $matches) ||
   218 					if ( preg_match("#^$match#", $request_match, $matches) ||
   205 						preg_match("#^$match#", urldecode($request_match), $matches) ) {
   219 						preg_match("#^$match#", urldecode($request_match), $matches) ) {
   206 
   220 
   207 						if ( $wp_rewrite->use_verbose_page_rules && preg_match( '/pagename=\$matches\[([0-9]+)\]/', $query, $varmatch ) ) {
   221 						if ( $wp_rewrite->use_verbose_page_rules && preg_match( '/pagename=\$matches\[([0-9]+)\]/', $query, $varmatch ) ) {
   208 							// This is a verbose page match, let's check to be sure about it.
   222 							// This is a verbose page match, let's check to be sure about it.
   209 							if ( ! get_page_by_path( $matches[ $varmatch[1] ] ) )
   223 							$page = get_page_by_path( $matches[ $varmatch[1] ] );
       
   224 							if ( ! $page ) {
   210 						 		continue;
   225 						 		continue;
       
   226 							}
       
   227 
       
   228 							$post_status_obj = get_post_status_object( $page->post_status );
       
   229 							if ( ! $post_status_obj->public && ! $post_status_obj->protected
       
   230 								&& ! $post_status_obj->private && $post_status_obj->exclude_from_search ) {
       
   231 								continue;
       
   232 							}
   211 						}
   233 						}
   212 
   234 
   213 						// Got a match.
   235 						// Got a match.
   214 						$this->matched_rule = $match;
   236 						$this->matched_rule = $match;
   215 						break;
   237 						break;
   233 				if ( '404' == $error )
   255 				if ( '404' == $error )
   234 					unset( $error, $_GET['error'] );
   256 					unset( $error, $_GET['error'] );
   235 			}
   257 			}
   236 
   258 
   237 			// If req_uri is empty or if it is a request for ourself, unset error.
   259 			// If req_uri is empty or if it is a request for ourself, unset error.
   238 			if ( empty($request) || $req_uri == $self || strpos($_SERVER['PHP_SELF'], 'wp-admin/') !== false ) {
   260 			if ( empty($requested_path) || $requested_file == $self || strpos($_SERVER['PHP_SELF'], 'wp-admin/') !== false ) {
   239 				unset( $error, $_GET['error'] );
   261 				unset( $error, $_GET['error'] );
   240 
   262 
   241 				if ( isset($perma_query_vars) && strpos($_SERVER['PHP_SELF'], 'wp-admin/') !== false )
   263 				if ( isset($perma_query_vars) && strpos($_SERVER['PHP_SELF'], 'wp-admin/') !== false )
   242 					unset( $perma_query_vars );
   264 					unset( $perma_query_vars );
   243 
   265 
   244 				$this->did_permalink = false;
   266 				$this->did_permalink = false;
   245 			}
   267 			}
   246 		}
   268 		}
   247 
   269 
   248 		/**
   270 		/**
   249 		 * Filter the query variables whitelist before processing.
   271 		 * Filters the query variables whitelist before processing.
   250 		 *
   272 		 *
   251 		 * Allows (publicly allowed) query vars to be added, removed, or changed prior
   273 		 * Allows (publicly allowed) query vars to be added, removed, or changed prior
   252 		 * to executing the query. Needed to allow custom rewrite rules using your own arguments
   274 		 * to executing the query. Needed to allow custom rewrite rules using your own arguments
   253 		 * to work, or any other custom query variables you want to be publicly available.
   275 		 * to work, or any other custom query variables you want to be publicly available.
   254 		 *
   276 		 *
   256 		 *
   278 		 *
   257 		 * @param array $public_query_vars The array of whitelisted query variables.
   279 		 * @param array $public_query_vars The array of whitelisted query variables.
   258 		 */
   280 		 */
   259 		$this->public_query_vars = apply_filters( 'query_vars', $this->public_query_vars );
   281 		$this->public_query_vars = apply_filters( 'query_vars', $this->public_query_vars );
   260 
   282 
   261 		foreach ( get_post_types( array(), 'objects' ) as $post_type => $t )
   283 		foreach ( get_post_types( array(), 'objects' ) as $post_type => $t ) {
   262 			if ( $t->query_var )
   284 			if ( is_post_type_viewable( $t ) && $t->query_var ) {
   263 				$post_type_query_vars[$t->query_var] = $post_type;
   285 				$post_type_query_vars[$t->query_var] = $post_type;
       
   286 			}
       
   287 		}
   264 
   288 
   265 		foreach ( $this->public_query_vars as $wpvar ) {
   289 		foreach ( $this->public_query_vars as $wpvar ) {
   266 			if ( isset( $this->extra_query_vars[$wpvar] ) )
   290 			if ( isset( $this->extra_query_vars[$wpvar] ) )
   267 				$this->query_vars[$wpvar] = $this->extra_query_vars[$wpvar];
   291 				$this->query_vars[$wpvar] = $this->extra_query_vars[$wpvar];
   268 			elseif ( isset( $_POST[$wpvar] ) )
   292 			elseif ( isset( $_POST[$wpvar] ) )
   293 		// Convert urldecoded spaces back into +
   317 		// Convert urldecoded spaces back into +
   294 		foreach ( get_taxonomies( array() , 'objects' ) as $taxonomy => $t )
   318 		foreach ( get_taxonomies( array() , 'objects' ) as $taxonomy => $t )
   295 			if ( $t->query_var && isset( $this->query_vars[$t->query_var] ) )
   319 			if ( $t->query_var && isset( $this->query_vars[$t->query_var] ) )
   296 				$this->query_vars[$t->query_var] = str_replace( ' ', '+', $this->query_vars[$t->query_var] );
   320 				$this->query_vars[$t->query_var] = str_replace( ' ', '+', $this->query_vars[$t->query_var] );
   297 
   321 
       
   322 		// Don't allow non-publicly queryable taxonomies to be queried from the front end.
       
   323 		if ( ! is_admin() ) {
       
   324 			foreach ( get_taxonomies( array( 'publicly_queryable' => false ), 'objects' ) as $taxonomy => $t ) {
       
   325 				/*
       
   326 				 * Disallow when set to the 'taxonomy' query var.
       
   327 				 * Non-publicly queryable taxonomies cannot register custom query vars. See register_taxonomy().
       
   328 				 */
       
   329 				if ( isset( $this->query_vars['taxonomy'] ) && $taxonomy === $this->query_vars['taxonomy'] ) {
       
   330 					unset( $this->query_vars['taxonomy'], $this->query_vars['term'] );
       
   331 				}
       
   332 			}
       
   333 		}
       
   334 
   298 		// Limit publicly queried post_types to those that are publicly_queryable
   335 		// Limit publicly queried post_types to those that are publicly_queryable
   299 		if ( isset( $this->query_vars['post_type']) ) {
   336 		if ( isset( $this->query_vars['post_type']) ) {
   300 			$queryable_post_types = get_post_types( array('publicly_queryable' => true) );
   337 			$queryable_post_types = get_post_types( array('publicly_queryable' => true) );
   301 			if ( ! is_array( $this->query_vars['post_type'] ) ) {
   338 			if ( ! is_array( $this->query_vars['post_type'] ) ) {
   302 				if ( ! in_array( $this->query_vars['post_type'], $queryable_post_types ) )
   339 				if ( ! in_array( $this->query_vars['post_type'], $queryable_post_types ) )
   304 			} else {
   341 			} else {
   305 				$this->query_vars['post_type'] = array_intersect( $this->query_vars['post_type'], $queryable_post_types );
   342 				$this->query_vars['post_type'] = array_intersect( $this->query_vars['post_type'], $queryable_post_types );
   306 			}
   343 			}
   307 		}
   344 		}
   308 
   345 
       
   346 		// Resolve conflicts between posts with numeric slugs and date archive queries.
       
   347 		$this->query_vars = wp_resolve_numeric_slug_conflicts( $this->query_vars );
       
   348 
   309 		foreach ( (array) $this->private_query_vars as $var) {
   349 		foreach ( (array) $this->private_query_vars as $var) {
   310 			if ( isset($this->extra_query_vars[$var]) )
   350 			if ( isset($this->extra_query_vars[$var]) )
   311 				$this->query_vars[$var] = $this->extra_query_vars[$var];
   351 				$this->query_vars[$var] = $this->extra_query_vars[$var];
   312 		}
   352 		}
   313 
   353 
   314 		if ( isset($error) )
   354 		if ( isset($error) )
   315 			$this->query_vars['error'] = $error;
   355 			$this->query_vars['error'] = $error;
   316 
   356 
   317 		/**
   357 		/**
   318 		 * Filter the array of parsed query variables.
   358 		 * Filters the array of parsed query variables.
   319 		 *
   359 		 *
   320 		 * @since 2.1.0
   360 		 * @since 2.1.0
   321 		 *
   361 		 *
   322 		 * @param array $query_vars The array of requested query variables.
   362 		 * @param array $query_vars The array of requested query variables.
   323 		 */
   363 		 */
   326 		/**
   366 		/**
   327 		 * Fires once all query variables for the current request have been parsed.
   367 		 * Fires once all query variables for the current request have been parsed.
   328 		 *
   368 		 *
   329 		 * @since 2.1.0
   369 		 * @since 2.1.0
   330 		 *
   370 		 *
   331 		 * @param WP &$this Current WordPress environment instance (passed by reference).
   371 		 * @param WP $this Current WordPress environment instance (passed by reference).
   332 		 */
   372 		 */
   333 		do_action_ref_array( 'parse_request', array( &$this ) );
   373 		do_action_ref_array( 'parse_request', array( &$this ) );
   334 	}
   374 	}
   335 
   375 
   336 	/**
   376 	/**
   337 	 * Send additional HTTP headers for caching, content type, etc.
   377 	 * Sends additional HTTP headers for caching, content type, etc.
   338 	 *
   378 	 *
   339 	 * Sets the X-Pingback header, 404 status (if 404), Content-type. If showing
   379 	 * Sets the Content-Type header. Sets the 'error' status (if passed) and optionally exits.
   340 	 * a feed, it will also send last-modified, etag, and 304 status if needed.
   380 	 * If showing a feed, it will also send Last-Modified, ETag, and 304 status if needed.
   341 	 *
   381 	 *
   342 	 * @since 2.0.0
   382 	 * @since 2.0.0
       
   383 	 * @since 4.4.0 `X-Pingback` header is added conditionally after posts have been queried in handle_404().
   343 	 */
   384 	 */
   344 	public function send_headers() {
   385 	public function send_headers() {
   345 		$headers = array('X-Pingback' => get_bloginfo('pingback_url'));
   386 		$headers = array();
   346 		$status = null;
   387 		$status = null;
   347 		$exit_required = false;
   388 		$exit_required = false;
   348 
   389 
   349 		if ( is_user_logged_in() )
   390 		if ( is_user_logged_in() )
   350 			$headers = array_merge($headers, wp_get_nocache_headers());
   391 			$headers = array_merge($headers, wp_get_nocache_headers());
   358 				$exit_required = true;
   399 				$exit_required = true;
   359 			}
   400 			}
   360 		} elseif ( empty( $this->query_vars['feed'] ) ) {
   401 		} elseif ( empty( $this->query_vars['feed'] ) ) {
   361 			$headers['Content-Type'] = get_option('html_type') . '; charset=' . get_option('blog_charset');
   402 			$headers['Content-Type'] = get_option('html_type') . '; charset=' . get_option('blog_charset');
   362 		} else {
   403 		} else {
   363 			// We're showing a feed, so WP is indeed the only thing that last changed
   404 			// Set the correct content type for feeds
   364 			if ( !empty($this->query_vars['withcomments'])
   405 			$type = $this->query_vars['feed'];
   365 				|| false !== strpos( $this->query_vars['feed'], 'comments-' )
   406 			if ( 'feed' == $this->query_vars['feed'] ) {
   366 				|| ( empty($this->query_vars['withoutcomments'])
   407 				$type = get_default_feed();
   367 					&& ( !empty($this->query_vars['p'])
   408 			}
   368 						|| !empty($this->query_vars['name'])
   409 			$headers['Content-Type'] = feed_content_type( $type ) . '; charset=' . get_option( 'blog_charset' );
   369 						|| !empty($this->query_vars['page_id'])
   410 
   370 						|| !empty($this->query_vars['pagename'])
   411 			// We're showing a feed, so WP is indeed the only thing that last changed.
   371 						|| !empty($this->query_vars['attachment'])
   412 			if ( ! empty( $this->query_vars['withcomments'] )
   372 						|| !empty($this->query_vars['attachment_id'])
   413 			     || false !== strpos( $this->query_vars['feed'], 'comments-' )
   373 					)
   414 			     || ( empty( $this->query_vars['withoutcomments'] )
   374 				)
   415 			          && ( ! empty( $this->query_vars['p'] )
   375 			)
   416 			               || ! empty( $this->query_vars['name'] )
   376 				$wp_last_modified = mysql2date('D, d M Y H:i:s', get_lastcommentmodified('GMT'), 0).' GMT';
   417 			               || ! empty( $this->query_vars['page_id'] )
   377 			else
   418 			               || ! empty( $this->query_vars['pagename'] )
   378 				$wp_last_modified = mysql2date('D, d M Y H:i:s', get_lastpostmodified('GMT'), 0).' GMT';
   419 			               || ! empty( $this->query_vars['attachment'] )
       
   420 			               || ! empty( $this->query_vars['attachment_id'] )
       
   421 			          )
       
   422 			     )
       
   423 			) {
       
   424 				$wp_last_modified = mysql2date( 'D, d M Y H:i:s', get_lastcommentmodified( 'GMT' ), false );
       
   425 			} else {
       
   426 				$wp_last_modified = mysql2date( 'D, d M Y H:i:s', get_lastpostmodified( 'GMT' ), false );
       
   427 			}
       
   428 
       
   429 			if ( ! $wp_last_modified ) {
       
   430 				$wp_last_modified = date( 'D, d M Y H:i:s' );
       
   431 			}
       
   432 
       
   433 			$wp_last_modified .= ' GMT';
       
   434 
   379 			$wp_etag = '"' . md5($wp_last_modified) . '"';
   435 			$wp_etag = '"' . md5($wp_last_modified) . '"';
   380 			$headers['Last-Modified'] = $wp_last_modified;
   436 			$headers['Last-Modified'] = $wp_last_modified;
   381 			$headers['ETag'] = $wp_etag;
   437 			$headers['ETag'] = $wp_etag;
   382 
   438 
   383 			// Support for Conditional GET
   439 			// Support for Conditional GET
   399 				$exit_required = true;
   455 				$exit_required = true;
   400 			}
   456 			}
   401 		}
   457 		}
   402 
   458 
   403 		/**
   459 		/**
   404 		 * Filter the HTTP headers before they're sent to the browser.
   460 		 * Filters the HTTP headers before they're sent to the browser.
   405 		 *
   461 		 *
   406 		 * @since 2.8.0
   462 		 * @since 2.8.0
   407 		 *
   463 		 *
   408 		 * @param array $headers The list of headers to be sent.
   464 		 * @param array $headers The list of headers to be sent.
   409 		 * @param WP    $this    Current WordPress environment instance.
   465 		 * @param WP    $this    Current WordPress environment instance.
   430 					}
   486 					}
   431 				}
   487 				}
   432 			}
   488 			}
   433 		}
   489 		}
   434 
   490 
   435 		foreach( (array) $headers as $name => $field_value )
   491 		foreach ( (array) $headers as $name => $field_value )
   436 			@header("{$name}: {$field_value}");
   492 			@header("{$name}: {$field_value}");
   437 
   493 
   438 		if ( $exit_required )
   494 		if ( $exit_required )
   439 			exit();
   495 			exit();
   440 
   496 
   441 		/**
   497 		/**
   442 		 * Fires once the requested HTTP headers for caching, content type, etc. have been sent.
   498 		 * Fires once the requested HTTP headers for caching, content type, etc. have been sent.
   443 		 *
   499 		 *
   444 		 * @since 2.1.0
   500 		 * @since 2.1.0
   445 		 *
   501 		 *
   446 		 * @param WP &$this Current WordPress environment instance (passed by reference).
   502 		 * @param WP $this Current WordPress environment instance (passed by reference).
   447 		 */
   503 		 */
   448 		do_action_ref_array( 'send_headers', array( &$this ) );
   504 		do_action_ref_array( 'send_headers', array( &$this ) );
   449 	}
   505 	}
   450 
   506 
   451 	/**
   507 	/**
   452 	 * Sets the query string property based off of the query variable property.
   508 	 * Sets the query string property based off of the query variable property.
   453 	 *
   509 	 *
   454 	 * The 'query_string' filter is deprecated, but still works. Plugins should
   510 	 * The {@see 'query_string'} filter is deprecated, but still works. Plugins should
   455 	 * use the 'request' filter instead.
   511 	 * use the {@see 'request'} filter instead.
   456 	 *
   512 	 *
   457 	 * @since 2.0.0
   513 	 * @since 2.0.0
   458 	 */
   514 	 */
   459 	public function build_query_string() {
   515 	public function build_query_string() {
   460 		$this->query_string = '';
   516 		$this->query_string = '';
   467 			}
   523 			}
   468 		}
   524 		}
   469 
   525 
   470 		if ( has_filter( 'query_string' ) ) {  // Don't bother filtering and parsing if no plugins are hooked in.
   526 		if ( has_filter( 'query_string' ) ) {  // Don't bother filtering and parsing if no plugins are hooked in.
   471 			/**
   527 			/**
   472 			 * Filter the query string before parsing.
   528 			 * Filters the query string before parsing.
   473 			 *
   529 			 *
   474 			 * @since 1.5.0
   530 			 * @since 1.5.0
   475 			 * @deprecated 2.1.0 Use 'query_vars' or 'request' filters instead.
   531 			 * @deprecated 2.1.0 Use 'query_vars' or 'request' filters instead.
   476 			 *
   532 			 *
   477 			 * @param string $query_string The query string to modify.
   533 			 * @param string $query_string The query string to modify.
   486 	 *
   542 	 *
   487 	 * The query_vars property will be extracted to the GLOBALS. So care should
   543 	 * The query_vars property will be extracted to the GLOBALS. So care should
   488 	 * be taken when naming global variables that might interfere with the
   544 	 * be taken when naming global variables that might interfere with the
   489 	 * WordPress environment.
   545 	 * WordPress environment.
   490 	 *
   546 	 *
   491 	 * @global string $query_string Query string for the loop.
   547 	 * @since 2.0.0
   492 	 * @global array $posts The found posts.
   548 	 *
       
   549 	 * @global WP_Query     $wp_query
       
   550 	 * @global string       $query_string Query string for the loop.
       
   551 	 * @global array        $posts The found posts.
   493 	 * @global WP_Post|null $post The current post, if available.
   552 	 * @global WP_Post|null $post The current post, if available.
   494 	 * @global string $request The SQL statement for the request.
   553 	 * @global string       $request The SQL statement for the request.
   495 	 * @global int $more Only set, if single page or post.
   554 	 * @global int          $more Only set, if single page or post.
   496 	 * @global int $single If single page or post. Only set, if single page or post.
   555 	 * @global int          $single If single page or post. Only set, if single page or post.
   497 	 * @global WP_User $authordata Only set, if author archive.
   556 	 * @global WP_User      $authordata Only set, if author archive.
   498 	 *
       
   499 	 * @since 2.0.0
       
   500 	 */
   557 	 */
   501 	public function register_globals() {
   558 	public function register_globals() {
   502 		global $wp_query;
   559 		global $wp_query;
   503 
   560 
   504 		// Extract updated query vars back into global namespace.
   561 		// Extract updated query vars back into global namespace.
   531 
   588 
   532 	/**
   589 	/**
   533 	 * Set up the Loop based on the query variables.
   590 	 * Set up the Loop based on the query variables.
   534 	 *
   591 	 *
   535 	 * @since 2.0.0
   592 	 * @since 2.0.0
       
   593 	 *
       
   594 	 * @global WP_Query $wp_the_query
   536 	 */
   595 	 */
   537 	public function query_posts() {
   596 	public function query_posts() {
   538 		global $wp_the_query;
   597 		global $wp_the_query;
   539 		$this->build_query_string();
   598 		$this->build_query_string();
   540 		$wp_the_query->query($this->query_vars);
   599 		$wp_the_query->query($this->query_vars);
   547 	 * any object (e.g. an existing-but-empty category, tag, author) and a 404 was not already
   606 	 * any object (e.g. an existing-but-empty category, tag, author) and a 404 was not already
   548 	 * issued, and if the request was not a search or the homepage.
   607 	 * issued, and if the request was not a search or the homepage.
   549 	 *
   608 	 *
   550 	 * Otherwise, issue a 200.
   609 	 * Otherwise, issue a 200.
   551 	 *
   610 	 *
   552 	 * @since 2.0.0
   611 	 * This sets headers after posts have been queried. handle_404() really means "handle status."
       
   612 	 * By inspecting the result of querying posts, seemingly successful requests can be switched to
       
   613 	 * a 404 so that canonical redirection logic can kick in.
       
   614 	 *
       
   615 	 * @since 2.0.0
       
   616      *
       
   617 	 * @global WP_Query $wp_query
   553  	 */
   618  	 */
   554 	public function handle_404() {
   619 	public function handle_404() {
   555 		global $wp_query;
   620 		global $wp_query;
   556 
   621 
       
   622 		/**
       
   623 		 * Filters whether to short-circuit default header status handling.
       
   624 		 *
       
   625 		 * Returning a non-false value from the filter will short-circuit the handling
       
   626 		 * and return early.
       
   627 		 *
       
   628 		 * @since 4.5.0
       
   629 		 *
       
   630 		 * @param bool     $preempt  Whether to short-circuit default header status handling. Default false.
       
   631 		 * @param WP_Query $wp_query WordPress Query object.
       
   632 		 */
       
   633 		if ( false !== apply_filters( 'pre_handle_404', false, $wp_query ) ) {
       
   634 			return;
       
   635 		}
       
   636 
   557 		// If we've already issued a 404, bail.
   637 		// If we've already issued a 404, bail.
   558 		if ( is_404() )
   638 		if ( is_404() )
   559 			return;
   639 			return;
   560 
   640 
   561 		// Never 404 for the admin, robots, or if we found posts.
   641 		// Never 404 for the admin, robots, or if we found posts.
   562 		if ( is_admin() || is_robots() || $wp_query->posts ) {
   642 		if ( is_admin() || is_robots() || $wp_query->posts ) {
   563 			status_header( 200 );
   643 
   564 			return;
   644 			$success = true;
       
   645 			if ( is_singular() ) {
       
   646 				$p = false;
       
   647 
       
   648 				if ( $wp_query->post instanceof WP_Post ) {
       
   649 					$p = clone $wp_query->post;
       
   650 				}
       
   651 
       
   652 				// Only set X-Pingback for single posts that allow pings.
       
   653 				if ( $p && pings_open( $p ) ) {
       
   654 					@header( 'X-Pingback: ' . get_bloginfo( 'pingback_url', 'display' ) );
       
   655 				}
       
   656 
       
   657 				// check for paged content that exceeds the max number of pages
       
   658 				$next = '<!--nextpage-->';
       
   659 				if ( $p && false !== strpos( $p->post_content, $next ) && ! empty( $this->query_vars['page'] ) ) {
       
   660 					$page = trim( $this->query_vars['page'], '/' );
       
   661 					$success = (int) $page <= ( substr_count( $p->post_content, $next ) + 1 );
       
   662 				}
       
   663 			}
       
   664 
       
   665 			if ( $success ) {
       
   666 				status_header( 200 );
       
   667 				return;
       
   668 			}
   565 		}
   669 		}
   566 
   670 
   567 		// We will 404 for paged queries, as no posts were found.
   671 		// We will 404 for paged queries, as no posts were found.
   568 		if ( ! is_paged() ) {
   672 		if ( ! is_paged() ) {
   569 
   673 
   594 	}
   698 	}
   595 
   699 
   596 	/**
   700 	/**
   597 	 * Sets up all of the variables required by the WordPress environment.
   701 	 * Sets up all of the variables required by the WordPress environment.
   598 	 *
   702 	 *
   599 	 * The action 'wp' has one parameter that references the WP object. It
   703 	 * The action {@see 'wp'} has one parameter that references the WP object. It
   600 	 * allows for accessing the properties and methods to further manipulate the
   704 	 * allows for accessing the properties and methods to further manipulate the
   601 	 * object.
   705 	 * object.
   602 	 *
   706 	 *
   603 	 * @since 2.0.0
   707 	 * @since 2.0.0
   604 	 *
   708 	 *
   605 	 * @param string|array $query_args Passed to {@link parse_request()}
   709 	 * @param string|array $query_args Passed to parse_request().
   606 	 */
   710 	 */
   607 	public function main($query_args = '') {
   711 	public function main($query_args = '') {
   608 		$this->init();
   712 		$this->init();
   609 		$this->parse_request($query_args);
   713 		$this->parse_request($query_args);
   610 		$this->send_headers();
   714 		$this->send_headers();
   615 		/**
   719 		/**
   616 		 * Fires once the WordPress environment has been set up.
   720 		 * Fires once the WordPress environment has been set up.
   617 		 *
   721 		 *
   618 		 * @since 2.1.0
   722 		 * @since 2.1.0
   619 		 *
   723 		 *
   620 		 * @param WP &$this Current WordPress environment instance (passed by reference).
   724 		 * @param WP $this Current WordPress environment instance (passed by reference).
   621 		 */
   725 		 */
   622 		do_action_ref_array( 'wp', array( &$this ) );
   726 		do_action_ref_array( 'wp', array( &$this ) );
   623 	}
   727 	}
   624 
       
   625 }
   728 }
   626 
       
   627 /**
       
   628  * Helper class to remove the need to use eval to replace $matches[] in query strings.
       
   629  *
       
   630  * @since 2.9.0
       
   631  */
       
   632 class WP_MatchesMapRegex {
       
   633 	/**
       
   634 	 * store for matches
       
   635 	 *
       
   636 	 * @access private
       
   637 	 * @var array
       
   638 	 */
       
   639 	private $_matches;
       
   640 
       
   641 	/**
       
   642 	 * store for mapping result
       
   643 	 *
       
   644 	 * @access public
       
   645 	 * @var string
       
   646 	 */
       
   647 	public $output;
       
   648 
       
   649 	/**
       
   650 	 * subject to perform mapping on (query string containing $matches[] references
       
   651 	 *
       
   652 	 * @access private
       
   653 	 * @var string
       
   654 	 */
       
   655 	private $_subject;
       
   656 
       
   657 	/**
       
   658 	 * regexp pattern to match $matches[] references
       
   659 	 *
       
   660 	 * @var string
       
   661 	 */
       
   662 	public $_pattern = '(\$matches\[[1-9]+[0-9]*\])'; // magic number
       
   663 
       
   664 	/**
       
   665 	 * constructor
       
   666 	 *
       
   667 	 * @param string $subject subject if regex
       
   668 	 * @param array  $matches data to use in map
       
   669 	 */
       
   670 	public function __construct($subject, $matches) {
       
   671 		$this->_subject = $subject;
       
   672 		$this->_matches = $matches;
       
   673 		$this->output = $this->_map();
       
   674 	}
       
   675 
       
   676 	/**
       
   677 	 * Substitute substring matches in subject.
       
   678 	 *
       
   679 	 * static helper function to ease use
       
   680 	 *
       
   681 	 * @access public
       
   682 	 * @param string $subject subject
       
   683 	 * @param array  $matches data used for substitution
       
   684 	 * @return string
       
   685 	 */
       
   686 	public static function apply($subject, $matches) {
       
   687 		$oSelf = new WP_MatchesMapRegex($subject, $matches);
       
   688 		return $oSelf->output;
       
   689 	}
       
   690 
       
   691 	/**
       
   692 	 * do the actual mapping
       
   693 	 *
       
   694 	 * @access private
       
   695 	 * @return string
       
   696 	 */
       
   697 	private function _map() {
       
   698 		$callback = array($this, 'callback');
       
   699 		return preg_replace_callback($this->_pattern, $callback, $this->_subject);
       
   700 	}
       
   701 
       
   702 	/**
       
   703 	 * preg_replace_callback hook
       
   704 	 *
       
   705 	 * @access public
       
   706 	 * @param  array $matches preg_replace regexp matches
       
   707 	 * @return string
       
   708 	 */
       
   709 	public function callback($matches) {
       
   710 		$index = intval(substr($matches[0], 9, -1));
       
   711 		return ( isset( $this->_matches[$index] ) ? urlencode($this->_matches[$index]) : '' );
       
   712 	}
       
   713 
       
   714 }