/wp-includes/class-wp.php

  1. <?php 
  2. /** 
  3. * WordPress environment setup class. 
  4. * 
  5. * @package WordPress 
  6. * @since 2.0.0 
  7. */ 
  8. class WP { 
  9. /** 
  10. * Public query variables. 
  11. * 
  12. * Long list of public query variables. 
  13. * 
  14. * @since 2.0.0 
  15. * @access public 
  16. * @var array 
  17. */ 
  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', 'attachment', 'attachment_id', 'subpost', 'subpost_id', 'preview', 'robots', 'taxonomy', 'term', 'cpage', 'post_type', 'embed' ); 
  19.  
  20. /** 
  21. * Private query variables. 
  22. * 
  23. * Long list of private query variables. 
  24. * 
  25. * @since 2.0.0 
  26. * @access public 
  27. * @var array 
  28. */ 
  29. 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' ); 
  30.  
  31. /** 
  32. * Extra query variables set by the user. 
  33. * 
  34. * @since 2.1.0 
  35. * @access public 
  36. * @var array 
  37. */ 
  38. public $extra_query_vars = array(); 
  39.  
  40. /** 
  41. * Query variables for setting up the WordPress Query Loop. 
  42. * 
  43. * @since 2.0.0 
  44. * @access public 
  45. * @var array 
  46. */ 
  47. public $query_vars; 
  48.  
  49. /** 
  50. * String parsed to set the query variables. 
  51. * 
  52. * @since 2.0.0 
  53. * @access public 
  54. * @var string 
  55. */ 
  56. public $query_string; 
  57.  
  58. /** 
  59. * The request path, e.g. 2015/05/06. 
  60. * 
  61. * @since 2.0.0 
  62. * @access public 
  63. * @var string 
  64. */ 
  65. public $request; 
  66.  
  67. /** 
  68. * Rewrite rule the request matched. 
  69. * 
  70. * @since 2.0.0 
  71. * @access public 
  72. * @var string 
  73. */ 
  74. public $matched_rule; 
  75.  
  76. /** 
  77. * Rewrite query the request matched. 
  78. * 
  79. * @since 2.0.0 
  80. * @access public 
  81. * @var string 
  82. */ 
  83. public $matched_query; 
  84.  
  85. /** 
  86. * Whether already did the permalink. 
  87. * 
  88. * @since 2.0.0 
  89. * @access public 
  90. * @var bool 
  91. */ 
  92. public $did_permalink = false; 
  93.  
  94. /** 
  95. * Add name to list of public query variables. 
  96. * 
  97. * @since 2.1.0 
  98. * @access public 
  99. * 
  100. * @param string $qv Query variable name. 
  101. */ 
  102. public function add_query_var($qv) { 
  103. if ( !in_array($qv, $this->public_query_vars) ) 
  104. $this->public_query_vars[] = $qv; 
  105.  
  106. /** 
  107. * Removes a query variable from a list of public query variables. 
  108. * 
  109. * @since 4.5.0 
  110. * @access public 
  111. * 
  112. * @param string $name Query variable name. 
  113. */ 
  114. public function remove_query_var( $name ) { 
  115. $this->public_query_vars = array_diff( $this->public_query_vars, array( $name ) ); 
  116.  
  117. /** 
  118. * Set the value of a query variable. 
  119. * 
  120. * @since 2.3.0 
  121. * @access public 
  122. * 
  123. * @param string $key Query variable name. 
  124. * @param mixed $value Query variable value. 
  125. */ 
  126. public function set_query_var($key, $value) { 
  127. $this->query_vars[$key] = $value; 
  128.  
  129. /** 
  130. * Parse request to find correct WordPress query. 
  131. * 
  132. * Sets up the query variables based on the request. There are also many 
  133. * filters and actions that can be used to further manipulate the result. 
  134. * 
  135. * @since 2.0.0 
  136. * @access public 
  137. * 
  138. * @global WP_Rewrite $wp_rewrite 
  139. * 
  140. * @param array|string $extra_query_vars Set the extra query variables. 
  141. */ 
  142. public function parse_request($extra_query_vars = '') { 
  143. global $wp_rewrite; 
  144.  
  145. /** 
  146. * Filters whether to parse the request. 
  147. * 
  148. * @since 3.5.0 
  149. * 
  150. * @param bool $bool Whether or not to parse the request. Default true. 
  151. * @param WP $this Current WordPress environment instance. 
  152. * @param array|string $extra_query_vars Extra passed query variables. 
  153. */ 
  154. if ( ! apply_filters( 'do_parse_request', true, $this, $extra_query_vars ) ) 
  155. return; 
  156.  
  157. $this->query_vars = array(); 
  158. $post_type_query_vars = array(); 
  159.  
  160. if ( is_array( $extra_query_vars ) ) { 
  161. $this->extra_query_vars = & $extra_query_vars; 
  162. } elseif ( ! empty( $extra_query_vars ) ) { 
  163. parse_str( $extra_query_vars, $this->extra_query_vars ); 
  164. // Process PATH_INFO, REQUEST_URI, and 404 for permalinks. 
  165.  
  166. // Fetch the rewrite rules. 
  167. $rewrite = $wp_rewrite->wp_rewrite_rules(); 
  168.  
  169. if ( ! empty($rewrite) ) { 
  170. // If we match a rewrite rule, this will be cleared. 
  171. $error = '404'; 
  172. $this->did_permalink = true; 
  173.  
  174. $pathinfo = isset( $_SERVER['PATH_INFO'] ) ? $_SERVER['PATH_INFO'] : ''; 
  175. list( $pathinfo ) = explode( '?', $pathinfo ); 
  176. $pathinfo = str_replace( "%", "%25", $pathinfo ); 
  177.  
  178. list( $req_uri ) = explode( '?', $_SERVER['REQUEST_URI'] ); 
  179. $self = $_SERVER['PHP_SELF']; 
  180. $home_path = trim( parse_url( home_url(), PHP_URL_PATH ), '/' ); 
  181. $home_path_regex = sprintf( '|^%s|i', preg_quote( $home_path, '|' ) ); 
  182.  
  183. // Trim path info from the end and the leading home path from the 
  184. // front. For path info requests, this leaves us with the requesting 
  185. // filename, if any. For 404 requests, this leaves us with the 
  186. // requested permalink. 
  187. $req_uri = str_replace($pathinfo, '', $req_uri); 
  188. $req_uri = trim($req_uri, '/'); 
  189. $req_uri = preg_replace( $home_path_regex, '', $req_uri ); 
  190. $req_uri = trim($req_uri, '/'); 
  191. $pathinfo = trim($pathinfo, '/'); 
  192. $pathinfo = preg_replace( $home_path_regex, '', $pathinfo ); 
  193. $pathinfo = trim($pathinfo, '/'); 
  194. $self = trim($self, '/'); 
  195. $self = preg_replace( $home_path_regex, '', $self ); 
  196. $self = trim($self, '/'); 
  197.  
  198. // The requested permalink is in $pathinfo for path info requests and 
  199. // $req_uri for other requests. 
  200. if ( ! empty($pathinfo) && !preg_match('|^.*' . $wp_rewrite->index . '$|', $pathinfo) ) { 
  201. $requested_path = $pathinfo; 
  202. } else { 
  203. // If the request uri is the index, blank it out so that we don't try to match it against a rule. 
  204. if ( $req_uri == $wp_rewrite->index ) 
  205. $req_uri = ''; 
  206. $requested_path = $req_uri; 
  207. $requested_file = $req_uri; 
  208.  
  209. $this->request = $requested_path; 
  210.  
  211. // Look for matches. 
  212. $request_match = $requested_path; 
  213. if ( empty( $request_match ) ) { 
  214. // An empty request could only match against ^$ regex 
  215. if ( isset( $rewrite['$'] ) ) { 
  216. $this->matched_rule = '$'; 
  217. $query = $rewrite['$']; 
  218. $matches = array(''); 
  219. } else { 
  220. foreach ( (array) $rewrite as $match => $query ) { 
  221. // If the requested file is the anchor of the match, prepend it to the path info. 
  222. if ( ! empty($requested_file) && strpos($match, $requested_file) === 0 && $requested_file != $requested_path ) 
  223. $request_match = $requested_file . '/' . $requested_path; 
  224.  
  225. if ( preg_match("#^$match#", $request_match, $matches) || 
  226. preg_match("#^$match#", urldecode($request_match), $matches) ) { 
  227.  
  228. if ( $wp_rewrite->use_verbose_page_rules && preg_match( '/pagename=\$matches\[([0-9]+)\]/', $query, $varmatch ) ) { 
  229. // This is a verbose page match, let's check to be sure about it. 
  230. $page = get_page_by_path( $matches[ $varmatch[1] ] ); 
  231. if ( ! $page ) { 
  232. continue; 
  233.  
  234. $post_status_obj = get_post_status_object( $page->post_status ); 
  235. if ( ! $post_status_obj->public && ! $post_status_obj->protected 
  236. && ! $post_status_obj->private && $post_status_obj->exclude_from_search ) { 
  237. continue; 
  238.  
  239. // Got a match. 
  240. $this->matched_rule = $match; 
  241. break; 
  242.  
  243. if ( isset( $this->matched_rule ) ) { 
  244. // Trim the query of everything up to the '?'. 
  245. $query = preg_replace("!^.+\?!", '', $query); 
  246.  
  247. // Substitute the substring matches into the query. 
  248. $query = addslashes(WP_MatchesMapRegex::apply($query, $matches)); 
  249.  
  250. $this->matched_query = $query; 
  251.  
  252. // Parse the query. 
  253. parse_str($query, $perma_query_vars); 
  254.  
  255. // If we're processing a 404 request, clear the error var since we found something. 
  256. if ( '404' == $error ) 
  257. unset( $error, $_GET['error'] ); 
  258.  
  259. // If req_uri is empty or if it is a request for ourself, unset error. 
  260. if ( empty($requested_path) || $requested_file == $self || strpos($_SERVER['PHP_SELF'], 'wp-admin/') !== false ) { 
  261. unset( $error, $_GET['error'] ); 
  262.  
  263. if ( isset($perma_query_vars) && strpos($_SERVER['PHP_SELF'], 'wp-admin/') !== false ) 
  264. unset( $perma_query_vars ); 
  265.  
  266. $this->did_permalink = false; 
  267.  
  268. /** 
  269. * Filters the query variables whitelist before processing. 
  270. * 
  271. * Allows (publicly allowed) query vars to be added, removed, or changed prior 
  272. * to executing the query. Needed to allow custom rewrite rules using your own arguments 
  273. * to work, or any other custom query variables you want to be publicly available. 
  274. * 
  275. * @since 1.5.0 
  276. * 
  277. * @param array $public_query_vars The array of whitelisted query variables. 
  278. */ 
  279. $this->public_query_vars = apply_filters( 'query_vars', $this->public_query_vars ); 
  280.  
  281. foreach ( get_post_types( array(), 'objects' ) as $post_type => $t ) { 
  282. if ( is_post_type_viewable( $t ) && $t->query_var ) { 
  283. $post_type_query_vars[$t->query_var] = $post_type; 
  284.  
  285. foreach ( $this->public_query_vars as $wpvar ) { 
  286. if ( isset( $this->extra_query_vars[$wpvar] ) ) 
  287. $this->query_vars[$wpvar] = $this->extra_query_vars[$wpvar]; 
  288. elseif ( isset( $_POST[$wpvar] ) ) 
  289. $this->query_vars[$wpvar] = $_POST[$wpvar]; 
  290. elseif ( isset( $_GET[$wpvar] ) ) 
  291. $this->query_vars[$wpvar] = $_GET[$wpvar]; 
  292. elseif ( isset( $perma_query_vars[$wpvar] ) ) 
  293. $this->query_vars[$wpvar] = $perma_query_vars[$wpvar]; 
  294.  
  295. if ( !empty( $this->query_vars[$wpvar] ) ) { 
  296. if ( ! is_array( $this->query_vars[$wpvar] ) ) { 
  297. $this->query_vars[$wpvar] = (string) $this->query_vars[$wpvar]; 
  298. } else { 
  299. foreach ( $this->query_vars[$wpvar] as $vkey => $v ) { 
  300. if ( !is_object( $v ) ) { 
  301. $this->query_vars[$wpvar][$vkey] = (string) $v; 
  302.  
  303. if ( isset($post_type_query_vars[$wpvar] ) ) { 
  304. $this->query_vars['post_type'] = $post_type_query_vars[$wpvar]; 
  305. $this->query_vars['name'] = $this->query_vars[$wpvar]; 
  306.  
  307. // Convert urldecoded spaces back into + 
  308. foreach ( get_taxonomies( array() , 'objects' ) as $taxonomy => $t ) 
  309. if ( $t->query_var && isset( $this->query_vars[$t->query_var] ) ) 
  310. $this->query_vars[$t->query_var] = str_replace( ' ', '+', $this->query_vars[$t->query_var] ); 
  311.  
  312. // Don't allow non-publicly queryable taxonomies to be queried from the front end. 
  313. if ( ! is_admin() ) { 
  314. foreach ( get_taxonomies( array( 'publicly_queryable' => false ), 'objects' ) as $taxonomy => $t ) { 
  315. /** 
  316. * Disallow when set to the 'taxonomy' query var. 
  317. * Non-publicly queryable taxonomies cannot register custom query vars. See register_taxonomy(). 
  318. */ 
  319. if ( isset( $this->query_vars['taxonomy'] ) && $taxonomy === $this->query_vars['taxonomy'] ) { 
  320. unset( $this->query_vars['taxonomy'], $this->query_vars['term'] ); 
  321.  
  322. // Limit publicly queried post_types to those that are publicly_queryable 
  323. if ( isset( $this->query_vars['post_type']) ) { 
  324. $queryable_post_types = get_post_types( array('publicly_queryable' => true) ); 
  325. if ( ! is_array( $this->query_vars['post_type'] ) ) { 
  326. if ( ! in_array( $this->query_vars['post_type'], $queryable_post_types ) ) 
  327. unset( $this->query_vars['post_type'] ); 
  328. } else { 
  329. $this->query_vars['post_type'] = array_intersect( $this->query_vars['post_type'], $queryable_post_types ); 
  330.  
  331. // Resolve conflicts between posts with numeric slugs and date archive queries. 
  332. $this->query_vars = wp_resolve_numeric_slug_conflicts( $this->query_vars ); 
  333.  
  334. foreach ( (array) $this->private_query_vars as $var) { 
  335. if ( isset($this->extra_query_vars[$var]) ) 
  336. $this->query_vars[$var] = $this->extra_query_vars[$var]; 
  337.  
  338. if ( isset($error) ) 
  339. $this->query_vars['error'] = $error; 
  340.  
  341. /** 
  342. * Filters the array of parsed query variables. 
  343. * 
  344. * @since 2.1.0 
  345. * 
  346. * @param array $query_vars The array of requested query variables. 
  347. */ 
  348. $this->query_vars = apply_filters( 'request', $this->query_vars ); 
  349.  
  350. /** 
  351. * Fires once all query variables for the current request have been parsed. 
  352. * 
  353. * @since 2.1.0 
  354. * 
  355. * @param WP &$this Current WordPress environment instance (passed by reference). 
  356. */ 
  357. do_action_ref_array( 'parse_request', array( &$this ) ); 
  358.  
  359. /** 
  360. * Sends additional HTTP headers for caching, content type, etc. 
  361. * 
  362. * Sets the Content-Type header. Sets the 'error' status (if passed) and optionally exits. 
  363. * If showing a feed, it will also send Last-Modified, ETag, and 304 status if needed. 
  364. * 
  365. * @since 2.0.0 
  366. * @since 4.4.0 `X-Pingback` header is added conditionally after posts have been queried in handle_404(). 
  367. * @access public 
  368. */ 
  369. public function send_headers() { 
  370. $headers = array(); 
  371. $status = null; 
  372. $exit_required = false; 
  373.  
  374. if ( is_user_logged_in() ) 
  375. $headers = array_merge($headers, wp_get_nocache_headers()); 
  376. if ( ! empty( $this->query_vars['error'] ) ) { 
  377. $status = (int) $this->query_vars['error']; 
  378. if ( 404 === $status ) { 
  379. if ( ! is_user_logged_in() ) 
  380. $headers = array_merge($headers, wp_get_nocache_headers()); 
  381. $headers['Content-Type'] = get_option('html_type') . '; charset=' . get_option('blog_charset'); 
  382. } elseif ( in_array( $status, array( 403, 500, 502, 503 ) ) ) { 
  383. $exit_required = true; 
  384. } elseif ( empty( $this->query_vars['feed'] ) ) { 
  385. $headers['Content-Type'] = get_option('html_type') . '; charset=' . get_option('blog_charset'); 
  386. } else { 
  387. // Set the correct content type for feeds 
  388. $type = $this->query_vars['feed']; 
  389. if ( 'feed' == $this->query_vars['feed'] ) { 
  390. $type = get_default_feed(); 
  391. $headers['Content-Type'] = feed_content_type( $type ) . '; charset=' . get_option( 'blog_charset' ); 
  392.  
  393. // We're showing a feed, so WP is indeed the only thing that last changed. 
  394. if ( ! empty( $this->query_vars['withcomments'] ) 
  395. || false !== strpos( $this->query_vars['feed'], 'comments-' ) 
  396. || ( empty( $this->query_vars['withoutcomments'] ) 
  397. && ( ! empty( $this->query_vars['p'] ) 
  398. || ! empty( $this->query_vars['name'] ) 
  399. || ! empty( $this->query_vars['page_id'] ) 
  400. || ! empty( $this->query_vars['pagename'] ) 
  401. || ! empty( $this->query_vars['attachment'] ) 
  402. || ! empty( $this->query_vars['attachment_id'] ) 
  403. ) { 
  404. $wp_last_modified = mysql2date( 'D, d M Y H:i:s', get_lastcommentmodified( 'GMT' ), false ); 
  405. } else { 
  406. $wp_last_modified = mysql2date( 'D, d M Y H:i:s', get_lastpostmodified( 'GMT' ), false ); 
  407.  
  408. if ( ! $wp_last_modified ) { 
  409. $wp_last_modified = date( 'D, d M Y H:i:s' ); 
  410.  
  411. $wp_last_modified .= ' GMT'; 
  412.  
  413. $wp_etag = '"' . md5($wp_last_modified) . '"'; 
  414. $headers['Last-Modified'] = $wp_last_modified; 
  415. $headers['ETag'] = $wp_etag; 
  416.  
  417. // Support for Conditional GET 
  418. if (isset($_SERVER['HTTP_IF_NONE_MATCH'])) 
  419. $client_etag = wp_unslash( $_SERVER['HTTP_IF_NONE_MATCH'] ); 
  420. else $client_etag = false; 
  421.  
  422. $client_last_modified = empty($_SERVER['HTTP_IF_MODIFIED_SINCE']) ? '' : trim($_SERVER['HTTP_IF_MODIFIED_SINCE']); 
  423. // If string is empty, return 0. If not, attempt to parse into a timestamp 
  424. $client_modified_timestamp = $client_last_modified ? strtotime($client_last_modified) : 0; 
  425.  
  426. // Make a timestamp for our most recent modification... 
  427. $wp_modified_timestamp = strtotime($wp_last_modified); 
  428.  
  429. if ( ($client_last_modified && $client_etag) ? 
  430. (($client_modified_timestamp >= $wp_modified_timestamp) && ($client_etag == $wp_etag)) : 
  431. (($client_modified_timestamp >= $wp_modified_timestamp) || ($client_etag == $wp_etag)) ) { 
  432. $status = 304; 
  433. $exit_required = true; 
  434.  
  435. /** 
  436. * Filters the HTTP headers before they're sent to the browser. 
  437. * 
  438. * @since 2.8.0 
  439. * 
  440. * @param array $headers The list of headers to be sent. 
  441. * @param WP $this Current WordPress environment instance. 
  442. */ 
  443. $headers = apply_filters( 'wp_headers', $headers, $this ); 
  444.  
  445. if ( ! empty( $status ) ) 
  446. status_header( $status ); 
  447.  
  448. // If Last-Modified is set to false, it should not be sent (no-cache situation). 
  449. if ( isset( $headers['Last-Modified'] ) && false === $headers['Last-Modified'] ) { 
  450. unset( $headers['Last-Modified'] ); 
  451.  
  452. // In PHP 5.3+, make sure we are not sending a Last-Modified header. 
  453. if ( function_exists( 'header_remove' ) ) { 
  454. @header_remove( 'Last-Modified' ); 
  455. } else { 
  456. // In PHP 5.2, send an empty Last-Modified header, but only as a 
  457. // last resort to override a header already sent. #WP23021 
  458. foreach ( headers_list() as $header ) { 
  459. if ( 0 === stripos( $header, 'Last-Modified' ) ) { 
  460. $headers['Last-Modified'] = ''; 
  461. break; 
  462.  
  463. foreach ( (array) $headers as $name => $field_value ) 
  464. @header("{$name}: {$field_value}"); 
  465.  
  466. if ( $exit_required ) 
  467. exit(); 
  468.  
  469. /** 
  470. * Fires once the requested HTTP headers for caching, content type, etc. have been sent. 
  471. * 
  472. * @since 2.1.0 
  473. * 
  474. * @param WP &$this Current WordPress environment instance (passed by reference). 
  475. */ 
  476. do_action_ref_array( 'send_headers', array( &$this ) ); 
  477.  
  478. /** 
  479. * Sets the query string property based off of the query variable property. 
  480. * 
  481. * The {@see 'query_string'} filter is deprecated, but still works. Plugins should 
  482. * use the {@see 'request'} filter instead. 
  483. * 
  484. * @since 2.0.0 
  485. * @access public 
  486. */ 
  487. public function build_query_string() { 
  488. $this->query_string = ''; 
  489. foreach ( (array) array_keys($this->query_vars) as $wpvar) { 
  490. if ( '' != $this->query_vars[$wpvar] ) { 
  491. $this->query_string .= (strlen($this->query_string) < 1) ? '' : '&'; 
  492. if ( !is_scalar($this->query_vars[$wpvar]) ) // Discard non-scalars. 
  493. continue; 
  494. $this->query_string .= $wpvar . '=' . rawurlencode($this->query_vars[$wpvar]); 
  495.  
  496. if ( has_filter( 'query_string' ) ) { // Don't bother filtering and parsing if no plugins are hooked in. 
  497. /** 
  498. * Filters the query string before parsing. 
  499. * 
  500. * @since 1.5.0 
  501. * @deprecated 2.1.0 Use 'query_vars' or 'request' filters instead. 
  502. * 
  503. * @param string $query_string The query string to modify. 
  504. */ 
  505. $this->query_string = apply_filters( 'query_string', $this->query_string ); 
  506. parse_str($this->query_string, $this->query_vars); 
  507.  
  508. /** 
  509. * Set up the WordPress Globals. 
  510. * 
  511. * The query_vars property will be extracted to the GLOBALS. So care should 
  512. * be taken when naming global variables that might interfere with the 
  513. * WordPress environment. 
  514. * 
  515. * @since 2.0.0 
  516. * @access public 
  517. * 
  518. * @global WP_Query $wp_query 
  519. * @global string $query_string Query string for the loop. 
  520. * @global array $posts The found posts. 
  521. * @global WP_Post|null $post The current post, if available. 
  522. * @global string $request The SQL statement for the request. 
  523. * @global int $more Only set, if single page or post. 
  524. * @global int $single If single page or post. Only set, if single page or post. 
  525. * @global WP_User $authordata Only set, if author archive. 
  526. */ 
  527. public function register_globals() { 
  528. global $wp_query; 
  529.  
  530. // Extract updated query vars back into global namespace. 
  531. foreach ( (array) $wp_query->query_vars as $key => $value ) { 
  532. $GLOBALS[ $key ] = $value; 
  533.  
  534. $GLOBALS['query_string'] = $this->query_string; 
  535. $GLOBALS['posts'] = & $wp_query->posts; 
  536. $GLOBALS['post'] = isset( $wp_query->post ) ? $wp_query->post : null; 
  537. $GLOBALS['request'] = $wp_query->request; 
  538.  
  539. if ( $wp_query->is_single() || $wp_query->is_page() ) { 
  540. $GLOBALS['more'] = 1; 
  541. $GLOBALS['single'] = 1; 
  542.  
  543. if ( $wp_query->is_author() && isset( $wp_query->post ) ) 
  544. $GLOBALS['authordata'] = get_userdata( $wp_query->post->post_author ); 
  545.  
  546. /** 
  547. * Set up the current user. 
  548. * 
  549. * @since 2.0.0 
  550. * @access public 
  551. */ 
  552. public function init() { 
  553. wp_get_current_user(); 
  554.  
  555. /** 
  556. * Set up the Loop based on the query variables. 
  557. * 
  558. * @since 2.0.0 
  559. * @access public 
  560. * 
  561. * @global WP_Query $wp_the_query 
  562. */ 
  563. public function query_posts() { 
  564. global $wp_the_query; 
  565. $this->build_query_string(); 
  566. $wp_the_query->query($this->query_vars); 
  567.  
  568. /** 
  569. * Set the Headers for 404, if nothing is found for requested URL. 
  570. * 
  571. * Issue a 404 if a request doesn't match any posts and doesn't match 
  572. * any object (e.g. an existing-but-empty category, tag, author) and a 404 was not already 
  573. * issued, and if the request was not a search or the homepage. 
  574. * 
  575. * Otherwise, issue a 200. 
  576. * 
  577. * This sets headers after posts have been queried. handle_404() really means "handle status." 
  578. * By inspecting the result of querying posts, seemingly successful requests can be switched to 
  579. * a 404 so that canonical redirection logic can kick in. 
  580. * 
  581. * @since 2.0.0 
  582. * @access public 
  583. * 
  584. * @global WP_Query $wp_query 
  585. */ 
  586. public function handle_404() { 
  587. global $wp_query; 
  588.  
  589. /** 
  590. * Filters whether to short-circuit default header status handling. 
  591. * 
  592. * Returning a non-false value from the filter will short-circuit the handling 
  593. * and return early. 
  594. * 
  595. * @since 4.5.0 
  596. * 
  597. * @param bool $preempt Whether to short-circuit default header status handling. Default false. 
  598. * @param WP_Query $wp_query WordPress Query object. 
  599. */ 
  600. if ( false !== apply_filters( 'pre_handle_404', false, $wp_query ) ) { 
  601. return; 
  602.  
  603. // If we've already issued a 404, bail. 
  604. if ( is_404() ) 
  605. return; 
  606.  
  607. // Never 404 for the admin, robots, or if we found posts. 
  608. if ( is_admin() || is_robots() || $wp_query->posts ) { 
  609.  
  610. $success = true; 
  611. if ( is_singular() ) { 
  612. $p = false; 
  613.  
  614. if ( $wp_query->post instanceof WP_Post ) { 
  615. $p = clone $wp_query->post; 
  616.  
  617. // Only set X-Pingback for single posts that allow pings. 
  618. if ( $p && pings_open( $p ) ) { 
  619. @header( 'X-Pingback: ' . get_bloginfo( 'pingback_url', 'display' ) ); 
  620.  
  621. // check for paged content that exceeds the max number of pages 
  622. $next = '<!--nextpage-->'; 
  623. if ( $p && false !== strpos( $p->post_content, $next ) && ! empty( $this->query_vars['page'] ) ) { 
  624. $page = trim( $this->query_vars['page'], '/' ); 
  625. $success = (int) $page <= ( substr_count( $p->post_content, $next ) + 1 ); 
  626.  
  627. if ( $success ) { 
  628. status_header( 200 ); 
  629. return; 
  630.  
  631. // We will 404 for paged queries, as no posts were found. 
  632. if ( ! is_paged() ) { 
  633.  
  634. // Don't 404 for authors without posts as long as they matched an author on this site. 
  635. $author = get_query_var( 'author' ); 
  636. if ( is_author() && is_numeric( $author ) && $author > 0 && is_user_member_of_blog( $author ) ) { 
  637. status_header( 200 ); 
  638. return; 
  639.  
  640. // Don't 404 for these queries if they matched an object. 
  641. if ( ( is_tag() || is_category() || is_tax() || is_post_type_archive() ) && get_queried_object() ) { 
  642. status_header( 200 ); 
  643. return; 
  644.  
  645. // Don't 404 for these queries either. 
  646. if ( is_home() || is_search() || is_feed() ) { 
  647. status_header( 200 ); 
  648. return; 
  649.  
  650. // Guess it's time to 404. 
  651. $wp_query->set_404(); 
  652. status_header( 404 ); 
  653. nocache_headers(); 
  654.  
  655. /** 
  656. * Sets up all of the variables required by the WordPress environment. 
  657. * 
  658. * The action {@see 'wp'} has one parameter that references the WP object. It 
  659. * allows for accessing the properties and methods to further manipulate the 
  660. * object. 
  661. * 
  662. * @since 2.0.0 
  663. * @access public 
  664. * 
  665. * @param string|array $query_args Passed to parse_request(). 
  666. */ 
  667. public function main($query_args = '') { 
  668. $this->init(); 
  669. $this->parse_request($query_args); 
  670. $this->send_headers(); 
  671. $this->query_posts(); 
  672. $this->handle_404(); 
  673. $this->register_globals(); 
  674.  
  675. /** 
  676. * Fires once the WordPress environment has been set up. 
  677. * 
  678. * @since 2.1.0 
  679. * 
  680. * @param WP &$this Current WordPress environment instance (passed by reference). 
  681. */ 
  682. do_action_ref_array( 'wp', array( &$this ) ); 
.