PageRenderTime 29ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/wp-includes/classes.php

https://gitlab.com/endomorphosis/reservationtelco
PHP | 1700 lines | 750 code | 207 blank | 743 comment | 214 complexity | 95bd2c5dc19e54b9154c6e8f22477707 MD5 | raw file
  1. <?php
  2. /**
  3. * Holds Most of the WordPress classes.
  4. *
  5. * Some of the other classes are contained in other files. For example, the
  6. * WordPress cache is in cache.php and the WordPress roles API is in
  7. * capabilities.php. The third party libraries are contained in their own
  8. * separate files.
  9. *
  10. * @package WordPress
  11. */
  12. /**
  13. * WordPress environment setup class.
  14. *
  15. * @package WordPress
  16. * @since 2.0.0
  17. */
  18. class WP {
  19. /**
  20. * Public query variables.
  21. *
  22. * Long list of public query variables.
  23. *
  24. * @since 2.0.0
  25. * @access public
  26. * @var array
  27. */
  28. var $public_query_vars = array('m', 'p', 'posts', 'w', 'cat', 'withcomments', 'withoutcomments', 's', 'search', 'exact', 'sentence', 'debug', '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');
  29. /**
  30. * Private query variables.
  31. *
  32. * Long list of private query variables.
  33. *
  34. * @since 2.0.0
  35. * @var array
  36. */
  37. var $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');
  38. /**
  39. * Extra query variables set by the user.
  40. *
  41. * @since 2.1.0
  42. * @var array
  43. */
  44. var $extra_query_vars = array();
  45. /**
  46. * Query variables for setting up the WordPress Query Loop.
  47. *
  48. * @since 2.0.0
  49. * @var array
  50. */
  51. var $query_vars;
  52. /**
  53. * String parsed to set the query variables.
  54. *
  55. * @since 2.0.0
  56. * @var string
  57. */
  58. var $query_string;
  59. /**
  60. * Permalink or requested URI.
  61. *
  62. * @since 2.0.0
  63. * @var string
  64. */
  65. var $request;
  66. /**
  67. * Rewrite rule the request matched.
  68. *
  69. * @since 2.0.0
  70. * @var string
  71. */
  72. var $matched_rule;
  73. /**
  74. * Rewrite query the request matched.
  75. *
  76. * @since 2.0.0
  77. * @var string
  78. */
  79. var $matched_query;
  80. /**
  81. * Whether already did the permalink.
  82. *
  83. * @since 2.0.0
  84. * @var bool
  85. */
  86. var $did_permalink = false;
  87. /**
  88. * Add name to list of public query variables.
  89. *
  90. * @since 2.1.0
  91. *
  92. * @param string $qv Query variable name.
  93. */
  94. function add_query_var($qv) {
  95. if ( !in_array($qv, $this->public_query_vars) )
  96. $this->public_query_vars[] = $qv;
  97. }
  98. /**
  99. * Set the value of a query variable.
  100. *
  101. * @since 2.3.0
  102. *
  103. * @param string $key Query variable name.
  104. * @param mixed $value Query variable value.
  105. */
  106. function set_query_var($key, $value) {
  107. $this->query_vars[$key] = $value;
  108. }
  109. /**
  110. * Parse request to find correct WordPress query.
  111. *
  112. * Sets up the query variables based on the request. There are also many
  113. * filters and actions that can be used to further manipulate the result.
  114. *
  115. * @since 2.0.0
  116. *
  117. * @param array|string $extra_query_vars Set the extra query variables.
  118. */
  119. function parse_request($extra_query_vars = '') {
  120. global $wp_rewrite;
  121. $this->query_vars = array();
  122. $taxonomy_query_vars = array();
  123. $post_type_query_vars = array();
  124. if ( is_array($extra_query_vars) )
  125. $this->extra_query_vars = & $extra_query_vars;
  126. else if (! empty($extra_query_vars))
  127. parse_str($extra_query_vars, $this->extra_query_vars);
  128. // Process PATH_INFO, REQUEST_URI, and 404 for permalinks.
  129. // Fetch the rewrite rules.
  130. $rewrite = $wp_rewrite->wp_rewrite_rules();
  131. if ( ! empty($rewrite) ) {
  132. // If we match a rewrite rule, this will be cleared.
  133. $error = '404';
  134. $this->did_permalink = true;
  135. if ( isset($_SERVER['PATH_INFO']) )
  136. $pathinfo = $_SERVER['PATH_INFO'];
  137. else
  138. $pathinfo = '';
  139. $pathinfo_array = explode('?', $pathinfo);
  140. $pathinfo = str_replace("%", "%25", $pathinfo_array[0]);
  141. $req_uri = $_SERVER['REQUEST_URI'];
  142. $req_uri_array = explode('?', $req_uri);
  143. $req_uri = $req_uri_array[0];
  144. $self = $_SERVER['PHP_SELF'];
  145. $home_path = parse_url(home_url());
  146. if ( isset($home_path['path']) )
  147. $home_path = $home_path['path'];
  148. else
  149. $home_path = '';
  150. $home_path = trim($home_path, '/');
  151. // Trim path info from the end and the leading home path from the
  152. // front. For path info requests, this leaves us with the requesting
  153. // filename, if any. For 404 requests, this leaves us with the
  154. // requested permalink.
  155. $req_uri = str_replace($pathinfo, '', rawurldecode($req_uri));
  156. $req_uri = trim($req_uri, '/');
  157. $req_uri = preg_replace("|^$home_path|", '', $req_uri);
  158. $req_uri = trim($req_uri, '/');
  159. $pathinfo = trim($pathinfo, '/');
  160. $pathinfo = preg_replace("|^$home_path|", '', $pathinfo);
  161. $pathinfo = trim($pathinfo, '/');
  162. $self = trim($self, '/');
  163. $self = preg_replace("|^$home_path|", '', $self);
  164. $self = trim($self, '/');
  165. // The requested permalink is in $pathinfo for path info requests and
  166. // $req_uri for other requests.
  167. if ( ! empty($pathinfo) && !preg_match('|^.*' . $wp_rewrite->index . '$|', $pathinfo) ) {
  168. $request = $pathinfo;
  169. } else {
  170. // If the request uri is the index, blank it out so that we don't try to match it against a rule.
  171. if ( $req_uri == $wp_rewrite->index )
  172. $req_uri = '';
  173. $request = $req_uri;
  174. }
  175. $this->request = $request;
  176. // Look for matches.
  177. $request_match = $request;
  178. foreach ( (array) $rewrite as $match => $query) {
  179. // Don't try to match against AtomPub calls
  180. if ( $req_uri == 'wp-app.php' )
  181. break;
  182. // If the requesting file is the anchor of the match, prepend it
  183. // to the path info.
  184. if ( (! empty($req_uri)) && (strpos($match, $req_uri) === 0) && ($req_uri != $request) )
  185. $request_match = $req_uri . '/' . $request;
  186. if ( preg_match("#^$match#", $request_match, $matches) ||
  187. preg_match("#^$match#", urldecode($request_match), $matches) ) {
  188. // Got a match.
  189. $this->matched_rule = $match;
  190. // Trim the query of everything up to the '?'.
  191. $query = preg_replace("!^.+\?!", '', $query);
  192. // Substitute the substring matches into the query.
  193. $query = addslashes(WP_MatchesMapRegex::apply($query, $matches));
  194. $this->matched_query = $query;
  195. // Parse the query.
  196. parse_str($query, $perma_query_vars);
  197. // If we're processing a 404 request, clear the error var
  198. // since we found something.
  199. if ( isset($_GET['error']) )
  200. unset($_GET['error']);
  201. if ( isset($error) )
  202. unset($error);
  203. break;
  204. }
  205. }
  206. // If req_uri is empty or if it is a request for ourself, unset error.
  207. if ( empty($request) || $req_uri == $self || strpos($_SERVER['PHP_SELF'], 'wp-admin/') !== false ) {
  208. if ( isset($_GET['error']) )
  209. unset($_GET['error']);
  210. if ( isset($error) )
  211. unset($error);
  212. if ( isset($perma_query_vars) && strpos($_SERVER['PHP_SELF'], 'wp-admin/') !== false )
  213. unset($perma_query_vars);
  214. $this->did_permalink = false;
  215. }
  216. }
  217. $this->public_query_vars = apply_filters('query_vars', $this->public_query_vars);
  218. foreach ( $GLOBALS['wp_taxonomies'] as $taxonomy => $t )
  219. if ( $t->query_var )
  220. $taxonomy_query_vars[$t->query_var] = $taxonomy;
  221. foreach ( $GLOBALS['wp_post_types'] as $post_type => $t )
  222. if ( $t->query_var )
  223. $post_type_query_vars[$t->query_var] = $post_type;
  224. for ( $i = 0; $i < count($this->public_query_vars); $i += 1 ) {
  225. $wpvar = $this->public_query_vars[$i];
  226. if ( isset($this->extra_query_vars[$wpvar]) )
  227. $this->query_vars[$wpvar] = $this->extra_query_vars[$wpvar];
  228. elseif ( isset($GLOBALS[$wpvar]) )
  229. $this->query_vars[$wpvar] = $GLOBALS[$wpvar];
  230. elseif ( !empty($_POST[$wpvar]) )
  231. $this->query_vars[$wpvar] = $_POST[$wpvar];
  232. elseif ( !empty($_GET[$wpvar]) )
  233. $this->query_vars[$wpvar] = $_GET[$wpvar];
  234. elseif ( !empty($perma_query_vars[$wpvar]) )
  235. $this->query_vars[$wpvar] = $perma_query_vars[$wpvar];
  236. if ( !empty( $this->query_vars[$wpvar] ) ) {
  237. $this->query_vars[$wpvar] = (string) $this->query_vars[$wpvar];
  238. if ( isset( $taxonomy_query_vars[$wpvar] ) ) {
  239. $this->query_vars['taxonomy'] = $taxonomy_query_vars[$wpvar];
  240. $this->query_vars['term'] = $this->query_vars[$wpvar];
  241. } elseif ( isset($post_type_query_vars[$wpvar] ) ) {
  242. $this->query_vars['post_type'] = $post_type_query_vars[$wpvar];
  243. $this->query_vars['name'] = $this->query_vars[$wpvar];
  244. }
  245. }
  246. }
  247. // Limit publicly queried post_types to those that are publicly_queryable
  248. if ( isset( $this->query_vars['post_type']) ) {
  249. $queryable_post_types = get_post_types( array('publicly_queryable' => true) );
  250. if ( ! in_array( $this->query_vars['post_type'], $queryable_post_types ) )
  251. unset( $this->query_vars['post_type'] );
  252. }
  253. foreach ( (array) $this->private_query_vars as $var) {
  254. if ( isset($this->extra_query_vars[$var]) )
  255. $this->query_vars[$var] = $this->extra_query_vars[$var];
  256. elseif ( isset($GLOBALS[$var]) && '' != $GLOBALS[$var] )
  257. $this->query_vars[$var] = $GLOBALS[$var];
  258. }
  259. if ( isset($error) )
  260. $this->query_vars['error'] = $error;
  261. $this->query_vars = apply_filters('request', $this->query_vars);
  262. do_action_ref_array('parse_request', array(&$this));
  263. }
  264. /**
  265. * Send additional HTTP headers for caching, content type, etc.
  266. *
  267. * Sets the X-Pingback header, 404 status (if 404), Content-type. If showing
  268. * a feed, it will also send last-modified, etag, and 304 status if needed.
  269. *
  270. * @since 2.0.0
  271. */
  272. function send_headers() {
  273. $headers = array('X-Pingback' => get_bloginfo('pingback_url'));
  274. $status = null;
  275. $exit_required = false;
  276. if ( is_user_logged_in() )
  277. $headers = array_merge($headers, wp_get_nocache_headers());
  278. if ( !empty($this->query_vars['error']) && '404' == $this->query_vars['error'] ) {
  279. $status = 404;
  280. if ( !is_user_logged_in() )
  281. $headers = array_merge($headers, wp_get_nocache_headers());
  282. $headers['Content-Type'] = get_option('html_type') . '; charset=' . get_option('blog_charset');
  283. } else if ( empty($this->query_vars['feed']) ) {
  284. $headers['Content-Type'] = get_option('html_type') . '; charset=' . get_option('blog_charset');
  285. } else {
  286. // We're showing a feed, so WP is indeed the only thing that last changed
  287. if ( !empty($this->query_vars['withcomments'])
  288. || ( empty($this->query_vars['withoutcomments'])
  289. && ( !empty($this->query_vars['p'])
  290. || !empty($this->query_vars['name'])
  291. || !empty($this->query_vars['page_id'])
  292. || !empty($this->query_vars['pagename'])
  293. || !empty($this->query_vars['attachment'])
  294. || !empty($this->query_vars['attachment_id'])
  295. )
  296. )
  297. )
  298. $wp_last_modified = mysql2date('D, d M Y H:i:s', get_lastcommentmodified('GMT'), 0).' GMT';
  299. else
  300. $wp_last_modified = mysql2date('D, d M Y H:i:s', get_lastpostmodified('GMT'), 0).' GMT';
  301. $wp_etag = '"' . md5($wp_last_modified) . '"';
  302. $headers['Last-Modified'] = $wp_last_modified;
  303. $headers['ETag'] = $wp_etag;
  304. // Support for Conditional GET
  305. if (isset($_SERVER['HTTP_IF_NONE_MATCH']))
  306. $client_etag = stripslashes(stripslashes($_SERVER['HTTP_IF_NONE_MATCH']));
  307. else $client_etag = false;
  308. $client_last_modified = empty($_SERVER['HTTP_IF_MODIFIED_SINCE']) ? '' : trim($_SERVER['HTTP_IF_MODIFIED_SINCE']);
  309. // If string is empty, return 0. If not, attempt to parse into a timestamp
  310. $client_modified_timestamp = $client_last_modified ? strtotime($client_last_modified) : 0;
  311. // Make a timestamp for our most recent modification...
  312. $wp_modified_timestamp = strtotime($wp_last_modified);
  313. if ( ($client_last_modified && $client_etag) ?
  314. (($client_modified_timestamp >= $wp_modified_timestamp) && ($client_etag == $wp_etag)) :
  315. (($client_modified_timestamp >= $wp_modified_timestamp) || ($client_etag == $wp_etag)) ) {
  316. $status = 304;
  317. $exit_required = true;
  318. }
  319. }
  320. $headers = apply_filters('wp_headers', $headers, $this);
  321. if ( ! empty( $status ) )
  322. status_header( $status );
  323. foreach( (array) $headers as $name => $field_value )
  324. @header("{$name}: {$field_value}");
  325. if ($exit_required)
  326. exit();
  327. do_action_ref_array('send_headers', array(&$this));
  328. }
  329. /**
  330. * Sets the query string property based off of the query variable property.
  331. *
  332. * The 'query_string' filter is deprecated, but still works. Plugins should
  333. * use the 'request' filter instead.
  334. *
  335. * @since 2.0.0
  336. */
  337. function build_query_string() {
  338. $this->query_string = '';
  339. foreach ( (array) array_keys($this->query_vars) as $wpvar) {
  340. if ( '' != $this->query_vars[$wpvar] ) {
  341. $this->query_string .= (strlen($this->query_string) < 1) ? '' : '&';
  342. if ( !is_scalar($this->query_vars[$wpvar]) ) // Discard non-scalars.
  343. continue;
  344. $this->query_string .= $wpvar . '=' . rawurlencode($this->query_vars[$wpvar]);
  345. }
  346. }
  347. // query_string filter deprecated. Use request filter instead.
  348. if ( has_filter('query_string') ) { // Don't bother filtering and parsing if no plugins are hooked in.
  349. $this->query_string = apply_filters('query_string', $this->query_string);
  350. parse_str($this->query_string, $this->query_vars);
  351. }
  352. }
  353. /**
  354. * Set up the WordPress Globals.
  355. *
  356. * The query_vars property will be extracted to the GLOBALS. So care should
  357. * be taken when naming global variables that might interfere with the
  358. * WordPress environment.
  359. *
  360. * @global string $query_string Query string for the loop.
  361. * @global int $more Only set, if single page or post.
  362. * @global int $single If single page or post. Only set, if single page or post.
  363. *
  364. * @since 2.0.0
  365. */
  366. function register_globals() {
  367. global $wp_query;
  368. // Extract updated query vars back into global namespace.
  369. foreach ( (array) $wp_query->query_vars as $key => $value) {
  370. $GLOBALS[$key] = $value;
  371. }
  372. $GLOBALS['query_string'] = $this->query_string;
  373. $GLOBALS['posts'] = & $wp_query->posts;
  374. $GLOBALS['post'] = $wp_query->post;
  375. $GLOBALS['request'] = $wp_query->request;
  376. if ( is_single() || is_page() ) {
  377. $GLOBALS['more'] = 1;
  378. $GLOBALS['single'] = 1;
  379. }
  380. }
  381. /**
  382. * Set up the current user.
  383. *
  384. * @since 2.0.0
  385. */
  386. function init() {
  387. wp_get_current_user();
  388. }
  389. /**
  390. * Set up the Loop based on the query variables.
  391. *
  392. * @uses WP::$query_vars
  393. * @since 2.0.0
  394. */
  395. function query_posts() {
  396. global $wp_the_query;
  397. $this->build_query_string();
  398. $wp_the_query->query($this->query_vars);
  399. }
  400. /**
  401. * Set the Headers for 404, if nothing is found for requested URL.
  402. *
  403. * Issue a 404 if a request doesn't match any posts and doesn't match
  404. * any object (e.g. an existing-but-empty category, tag, author) and a 404 was not already
  405. * issued, and if the request was not a search or the homepage.
  406. *
  407. * Otherwise, issue a 200.
  408. *
  409. * @since 2.0.0
  410. */
  411. function handle_404() {
  412. global $wp_query;
  413. if ( ( 0 == count( $wp_query->posts ) ) && !is_404() && !is_robots() && !is_search() && !is_home() ) {
  414. // Don't 404 for these queries if they matched an object.
  415. if ( ( is_tag() || is_category() || is_tax() || is_author() ) && $wp_query->get_queried_object() && !is_paged() ) {
  416. if ( !is_404() )
  417. status_header( 200 );
  418. return;
  419. }
  420. $wp_query->set_404();
  421. status_header( 404 );
  422. nocache_headers();
  423. } elseif ( !is_404() ) {
  424. status_header( 200 );
  425. }
  426. }
  427. /**
  428. * Sets up all of the variables required by the WordPress environment.
  429. *
  430. * The action 'wp' has one parameter that references the WP object. It
  431. * allows for accessing the properties and methods to further manipulate the
  432. * object.
  433. *
  434. * @since 2.0.0
  435. *
  436. * @param string|array $query_args Passed to {@link parse_request()}
  437. */
  438. function main($query_args = '') {
  439. $this->init();
  440. $this->parse_request($query_args);
  441. $this->send_headers();
  442. $this->query_posts();
  443. $this->handle_404();
  444. $this->register_globals();
  445. do_action_ref_array('wp', array(&$this));
  446. }
  447. /**
  448. * PHP4 Constructor - Does nothing.
  449. *
  450. * Call main() method when ready to run setup.
  451. *
  452. * @since 2.0.0
  453. *
  454. * @return WP
  455. */
  456. function WP() {
  457. // Empty.
  458. }
  459. }
  460. /**
  461. * WordPress Error class.
  462. *
  463. * Container for checking for WordPress errors and error messages. Return
  464. * WP_Error and use {@link is_wp_error()} to check if this class is returned.
  465. * Many core WordPress functions pass this class in the event of an error and
  466. * if not handled properly will result in code errors.
  467. *
  468. * @package WordPress
  469. * @since 2.1.0
  470. */
  471. class WP_Error {
  472. /**
  473. * Stores the list of errors.
  474. *
  475. * @since 2.1.0
  476. * @var array
  477. * @access private
  478. */
  479. var $errors = array();
  480. /**
  481. * Stores the list of data for error codes.
  482. *
  483. * @since 2.1.0
  484. * @var array
  485. * @access private
  486. */
  487. var $error_data = array();
  488. /**
  489. * PHP4 Constructor - Sets up error message.
  490. *
  491. * If code parameter is empty then nothing will be done. It is possible to
  492. * add multiple messages to the same code, but with other methods in the
  493. * class.
  494. *
  495. * All parameters are optional, but if the code parameter is set, then the
  496. * data parameter is optional.
  497. *
  498. * @since 2.1.0
  499. *
  500. * @param string|int $code Error code
  501. * @param string $message Error message
  502. * @param mixed $data Optional. Error data.
  503. * @return WP_Error
  504. */
  505. function WP_Error($code = '', $message = '', $data = '') {
  506. if ( empty($code) )
  507. return;
  508. $this->errors[$code][] = $message;
  509. if ( ! empty($data) )
  510. $this->error_data[$code] = $data;
  511. }
  512. /**
  513. * Retrieve all error codes.
  514. *
  515. * @since 2.1.0
  516. * @access public
  517. *
  518. * @return array List of error codes, if avaiable.
  519. */
  520. function get_error_codes() {
  521. if ( empty($this->errors) )
  522. return array();
  523. return array_keys($this->errors);
  524. }
  525. /**
  526. * Retrieve first error code available.
  527. *
  528. * @since 2.1.0
  529. * @access public
  530. *
  531. * @return string|int Empty string, if no error codes.
  532. */
  533. function get_error_code() {
  534. $codes = $this->get_error_codes();
  535. if ( empty($codes) )
  536. return '';
  537. return $codes[0];
  538. }
  539. /**
  540. * Retrieve all error messages or error messages matching code.
  541. *
  542. * @since 2.1.0
  543. *
  544. * @param string|int $code Optional. Retrieve messages matching code, if exists.
  545. * @return array Error strings on success, or empty array on failure (if using codee parameter).
  546. */
  547. function get_error_messages($code = '') {
  548. // Return all messages if no code specified.
  549. if ( empty($code) ) {
  550. $all_messages = array();
  551. foreach ( (array) $this->errors as $code => $messages )
  552. $all_messages = array_merge($all_messages, $messages);
  553. return $all_messages;
  554. }
  555. if ( isset($this->errors[$code]) )
  556. return $this->errors[$code];
  557. else
  558. return array();
  559. }
  560. /**
  561. * Get single error message.
  562. *
  563. * This will get the first message available for the code. If no code is
  564. * given then the first code available will be used.
  565. *
  566. * @since 2.1.0
  567. *
  568. * @param string|int $code Optional. Error code to retrieve message.
  569. * @return string
  570. */
  571. function get_error_message($code = '') {
  572. if ( empty($code) )
  573. $code = $this->get_error_code();
  574. $messages = $this->get_error_messages($code);
  575. if ( empty($messages) )
  576. return '';
  577. return $messages[0];
  578. }
  579. /**
  580. * Retrieve error data for error code.
  581. *
  582. * @since 2.1.0
  583. *
  584. * @param string|int $code Optional. Error code.
  585. * @return mixed Null, if no errors.
  586. */
  587. function get_error_data($code = '') {
  588. if ( empty($code) )
  589. $code = $this->get_error_code();
  590. if ( isset($this->error_data[$code]) )
  591. return $this->error_data[$code];
  592. return null;
  593. }
  594. /**
  595. * Append more error messages to list of error messages.
  596. *
  597. * @since 2.1.0
  598. * @access public
  599. *
  600. * @param string|int $code Error code.
  601. * @param string $message Error message.
  602. * @param mixed $data Optional. Error data.
  603. */
  604. function add($code, $message, $data = '') {
  605. $this->errors[$code][] = $message;
  606. if ( ! empty($data) )
  607. $this->error_data[$code] = $data;
  608. }
  609. /**
  610. * Add data for error code.
  611. *
  612. * The error code can only contain one error data.
  613. *
  614. * @since 2.1.0
  615. *
  616. * @param mixed $data Error data.
  617. * @param string|int $code Error code.
  618. */
  619. function add_data($data, $code = '') {
  620. if ( empty($code) )
  621. $code = $this->get_error_code();
  622. $this->error_data[$code] = $data;
  623. }
  624. }
  625. /**
  626. * Check whether variable is a WordPress Error.
  627. *
  628. * Looks at the object and if a WP_Error class. Does not check to see if the
  629. * parent is also WP_Error, so can't inherit WP_Error and still use this
  630. * function.
  631. *
  632. * @since 2.1.0
  633. *
  634. * @param mixed $thing Check if unknown variable is WordPress Error object.
  635. * @return bool True, if WP_Error. False, if not WP_Error.
  636. */
  637. function is_wp_error($thing) {
  638. if ( is_object($thing) && is_a($thing, 'WP_Error') )
  639. return true;
  640. return false;
  641. }
  642. /**
  643. * A class for displaying various tree-like structures.
  644. *
  645. * Extend the Walker class to use it, see examples at the below. Child classes
  646. * do not need to implement all of the abstract methods in the class. The child
  647. * only needs to implement the methods that are needed. Also, the methods are
  648. * not strictly abstract in that the parameter definition needs to be followed.
  649. * The child classes can have additional parameters.
  650. *
  651. * @package WordPress
  652. * @since 2.1.0
  653. * @abstract
  654. */
  655. class Walker {
  656. /**
  657. * What the class handles.
  658. *
  659. * @since 2.1.0
  660. * @var string
  661. * @access public
  662. */
  663. var $tree_type;
  664. /**
  665. * DB fields to use.
  666. *
  667. * @since 2.1.0
  668. * @var array
  669. * @access protected
  670. */
  671. var $db_fields;
  672. /**
  673. * Max number of pages walked by the paged walker
  674. *
  675. * @since 2.7.0
  676. * @var int
  677. * @access protected
  678. */
  679. var $max_pages = 1;
  680. /**
  681. * Starts the list before the elements are added.
  682. *
  683. * Additional parameters are used in child classes. The args parameter holds
  684. * additional values that may be used with the child class methods. This
  685. * method is called at the start of the output list.
  686. *
  687. * @since 2.1.0
  688. * @abstract
  689. *
  690. * @param string $output Passed by reference. Used to append additional content.
  691. */
  692. function start_lvl(&$output) {}
  693. /**
  694. * Ends the list of after the elements are added.
  695. *
  696. * Additional parameters are used in child classes. The args parameter holds
  697. * additional values that may be used with the child class methods. This
  698. * method finishes the list at the end of output of the elements.
  699. *
  700. * @since 2.1.0
  701. * @abstract
  702. *
  703. * @param string $output Passed by reference. Used to append additional content.
  704. */
  705. function end_lvl(&$output) {}
  706. /**
  707. * Start the element output.
  708. *
  709. * Additional parameters are used in child classes. The args parameter holds
  710. * additional values that may be used with the child class methods. Includes
  711. * the element output also.
  712. *
  713. * @since 2.1.0
  714. * @abstract
  715. *
  716. * @param string $output Passed by reference. Used to append additional content.
  717. */
  718. function start_el(&$output) {}
  719. /**
  720. * Ends the element output, if needed.
  721. *
  722. * Additional parameters are used in child classes. The args parameter holds
  723. * additional values that may be used with the child class methods.
  724. *
  725. * @since 2.1.0
  726. * @abstract
  727. *
  728. * @param string $output Passed by reference. Used to append additional content.
  729. */
  730. function end_el(&$output) {}
  731. /**
  732. * Traverse elements to create list from elements.
  733. *
  734. * Display one element if the element doesn't have any children otherwise,
  735. * display the element and its children. Will only traverse up to the max
  736. * depth and no ignore elements under that depth. It is possible to set the
  737. * max depth to include all depths, see walk() method.
  738. *
  739. * This method shouldn't be called directly, use the walk() method instead.
  740. *
  741. * @since 2.5.0
  742. *
  743. * @param object $element Data object
  744. * @param array $children_elements List of elements to continue traversing.
  745. * @param int $max_depth Max depth to traverse.
  746. * @param int $depth Depth of current element.
  747. * @param array $args
  748. * @param string $output Passed by reference. Used to append additional content.
  749. * @return null Null on failure with no changes to parameters.
  750. */
  751. function display_element( $element, &$children_elements, $max_depth, $depth=0, $args, &$output ) {
  752. if ( !$element )
  753. return;
  754. $id_field = $this->db_fields['id'];
  755. //display this element
  756. if ( is_array( $args[0] ) )
  757. $args[0]['has_children'] = ! empty( $children_elements[$element->$id_field] );
  758. $cb_args = array_merge( array(&$output, $element, $depth), $args);
  759. call_user_func_array(array(&$this, 'start_el'), $cb_args);
  760. $id = $element->$id_field;
  761. // descend only when the depth is right and there are childrens for this element
  762. if ( ($max_depth == 0 || $max_depth > $depth+1 ) && isset( $children_elements[$id]) ) {
  763. foreach( $children_elements[ $id ] as $child ){
  764. if ( !isset($newlevel) ) {
  765. $newlevel = true;
  766. //start the child delimiter
  767. $cb_args = array_merge( array(&$output, $depth), $args);
  768. call_user_func_array(array(&$this, 'start_lvl'), $cb_args);
  769. }
  770. $this->display_element( $child, $children_elements, $max_depth, $depth + 1, $args, $output );
  771. }
  772. unset( $children_elements[ $id ] );
  773. }
  774. if ( isset($newlevel) && $newlevel ){
  775. //end the child delimiter
  776. $cb_args = array_merge( array(&$output, $depth), $args);
  777. call_user_func_array(array(&$this, 'end_lvl'), $cb_args);
  778. }
  779. //end this element
  780. $cb_args = array_merge( array(&$output, $element, $depth), $args);
  781. call_user_func_array(array(&$this, 'end_el'), $cb_args);
  782. }
  783. /**
  784. * Display array of elements hierarchically.
  785. *
  786. * It is a generic function which does not assume any existing order of
  787. * elements. max_depth = -1 means flatly display every element. max_depth =
  788. * 0 means display all levels. max_depth > 0 specifies the number of
  789. * display levels.
  790. *
  791. * @since 2.1.0
  792. *
  793. * @param array $elements
  794. * @param int $max_depth
  795. * @return string
  796. */
  797. function walk( $elements, $max_depth) {
  798. $args = array_slice(func_get_args(), 2);
  799. $output = '';
  800. if ($max_depth < -1) //invalid parameter
  801. return $output;
  802. if (empty($elements)) //nothing to walk
  803. return $output;
  804. $id_field = $this->db_fields['id'];
  805. $parent_field = $this->db_fields['parent'];
  806. // flat display
  807. if ( -1 == $max_depth ) {
  808. $empty_array = array();
  809. foreach ( $elements as $e )
  810. $this->display_element( $e, $empty_array, 1, 0, $args, $output );
  811. return $output;
  812. }
  813. /*
  814. * need to display in hierarchical order
  815. * separate elements into two buckets: top level and children elements
  816. * children_elements is two dimensional array, eg.
  817. * children_elements[10][] contains all sub-elements whose parent is 10.
  818. */
  819. $top_level_elements = array();
  820. $children_elements = array();
  821. foreach ( $elements as $e) {
  822. if ( 0 == $e->$parent_field )
  823. $top_level_elements[] = $e;
  824. else
  825. $children_elements[ $e->$parent_field ][] = $e;
  826. }
  827. /*
  828. * when none of the elements is top level
  829. * assume the first one must be root of the sub elements
  830. */
  831. if ( empty($top_level_elements) ) {
  832. $first = array_slice( $elements, 0, 1 );
  833. $root = $first[0];
  834. $top_level_elements = array();
  835. $children_elements = array();
  836. foreach ( $elements as $e) {
  837. if ( $root->$parent_field == $e->$parent_field )
  838. $top_level_elements[] = $e;
  839. else
  840. $children_elements[ $e->$parent_field ][] = $e;
  841. }
  842. }
  843. foreach ( $top_level_elements as $e )
  844. $this->display_element( $e, $children_elements, $max_depth, 0, $args, $output );
  845. /*
  846. * if we are displaying all levels, and remaining children_elements is not empty,
  847. * then we got orphans, which should be displayed regardless
  848. */
  849. if ( ( $max_depth == 0 ) && count( $children_elements ) > 0 ) {
  850. $empty_array = array();
  851. foreach ( $children_elements as $orphans )
  852. foreach( $orphans as $op )
  853. $this->display_element( $op, $empty_array, 1, 0, $args, $output );
  854. }
  855. return $output;
  856. }
  857. /**
  858. * paged_walk() - produce a page of nested elements
  859. *
  860. * Given an array of hierarchical elements, the maximum depth, a specific page number,
  861. * and number of elements per page, this function first determines all top level root elements
  862. * belonging to that page, then lists them and all of their children in hierarchical order.
  863. *
  864. * @package WordPress
  865. * @since 2.7
  866. * @param $max_depth = 0 means display all levels; $max_depth > 0 specifies the number of display levels.
  867. * @param $page_num the specific page number, beginning with 1.
  868. * @return XHTML of the specified page of elements
  869. */
  870. function paged_walk( $elements, $max_depth, $page_num, $per_page ) {
  871. /* sanity check */
  872. if ( empty($elements) || $max_depth < -1 )
  873. return '';
  874. $args = array_slice( func_get_args(), 4 );
  875. $output = '';
  876. $id_field = $this->db_fields['id'];
  877. $parent_field = $this->db_fields['parent'];
  878. $count = -1;
  879. if ( -1 == $max_depth )
  880. $total_top = count( $elements );
  881. if ( $page_num < 1 || $per_page < 0 ) {
  882. // No paging
  883. $paging = false;
  884. $start = 0;
  885. if ( -1 == $max_depth )
  886. $end = $total_top;
  887. $this->max_pages = 1;
  888. } else {
  889. $paging = true;
  890. $start = ( (int)$page_num - 1 ) * (int)$per_page;
  891. $end = $start + $per_page;
  892. if ( -1 == $max_depth )
  893. $this->max_pages = ceil($total_top / $per_page);
  894. }
  895. // flat display
  896. if ( -1 == $max_depth ) {
  897. if ( !empty($args[0]['reverse_top_level']) ) {
  898. $elements = array_reverse( $elements );
  899. $oldstart = $start;
  900. $start = $total_top - $end;
  901. $end = $total_top - $oldstart;
  902. }
  903. $empty_array = array();
  904. foreach ( $elements as $e ) {
  905. $count++;
  906. if ( $count < $start )
  907. continue;
  908. if ( $count >= $end )
  909. break;
  910. $this->display_element( $e, $empty_array, 1, 0, $args, $output );
  911. }
  912. return $output;
  913. }
  914. /*
  915. * separate elements into two buckets: top level and children elements
  916. * children_elements is two dimensional array, eg.
  917. * children_elements[10][] contains all sub-elements whose parent is 10.
  918. */
  919. $top_level_elements = array();
  920. $children_elements = array();
  921. foreach ( $elements as $e) {
  922. if ( 0 == $e->$parent_field )
  923. $top_level_elements[] = $e;
  924. else
  925. $children_elements[ $e->$parent_field ][] = $e;
  926. }
  927. $total_top = count( $top_level_elements );
  928. if ( $paging )
  929. $this->max_pages = ceil($total_top / $per_page);
  930. else
  931. $end = $total_top;
  932. if ( !empty($args[0]['reverse_top_level']) ) {
  933. $top_level_elements = array_reverse( $top_level_elements );
  934. $oldstart = $start;
  935. $start = $total_top - $end;
  936. $end = $total_top - $oldstart;
  937. }
  938. if ( !empty($args[0]['reverse_children']) ) {
  939. foreach ( $children_elements as $parent => $children )
  940. $children_elements[$parent] = array_reverse( $children );
  941. }
  942. foreach ( $top_level_elements as $e ) {
  943. $count++;
  944. //for the last page, need to unset earlier children in order to keep track of orphans
  945. if ( $end >= $total_top && $count < $start )
  946. $this->unset_children( $e, $children_elements );
  947. if ( $count < $start )
  948. continue;
  949. if ( $count >= $end )
  950. break;
  951. $this->display_element( $e, $children_elements, $max_depth, 0, $args, $output );
  952. }
  953. if ( $end >= $total_top && count( $children_elements ) > 0 ) {
  954. $empty_array = array();
  955. foreach ( $children_elements as $orphans )
  956. foreach( $orphans as $op )
  957. $this->display_element( $op, $empty_array, 1, 0, $args, $output );
  958. }
  959. return $output;
  960. }
  961. function get_number_of_root_elements( $elements ){
  962. $num = 0;
  963. $parent_field = $this->db_fields['parent'];
  964. foreach ( $elements as $e) {
  965. if ( 0 == $e->$parent_field )
  966. $num++;
  967. }
  968. return $num;
  969. }
  970. // unset all the children for a given top level element
  971. function unset_children( $e, &$children_elements ){
  972. if ( !$e || !$children_elements )
  973. return;
  974. $id_field = $this->db_fields['id'];
  975. $id = $e->$id_field;
  976. if ( !empty($children_elements[$id]) && is_array($children_elements[$id]) )
  977. foreach ( (array) $children_elements[$id] as $child )
  978. $this->unset_children( $child, $children_elements );
  979. if ( isset($children_elements[$id]) )
  980. unset( $children_elements[$id] );
  981. }
  982. }
  983. /**
  984. * Create HTML list of pages.
  985. *
  986. * @package WordPress
  987. * @since 2.1.0
  988. * @uses Walker
  989. */
  990. class Walker_Page extends Walker {
  991. /**
  992. * @see Walker::$tree_type
  993. * @since 2.1.0
  994. * @var string
  995. */
  996. var $tree_type = 'page';
  997. /**
  998. * @see Walker::$db_fields
  999. * @since 2.1.0
  1000. * @todo Decouple this.
  1001. * @var array
  1002. */
  1003. var $db_fields = array ('parent' => 'post_parent', 'id' => 'ID');
  1004. /**
  1005. * @see Walker::start_lvl()
  1006. * @since 2.1.0
  1007. *
  1008. * @param string $output Passed by reference. Used to append additional content.
  1009. * @param int $depth Depth of page. Used for padding.
  1010. */
  1011. function start_lvl(&$output, $depth) {
  1012. $indent = str_repeat("\t", $depth);
  1013. $output .= "\n$indent<ul class='children'>\n";
  1014. }
  1015. /**
  1016. * @see Walker::end_lvl()
  1017. * @since 2.1.0
  1018. *
  1019. * @param string $output Passed by reference. Used to append additional content.
  1020. * @param int $depth Depth of page. Used for padding.
  1021. */
  1022. function end_lvl(&$output, $depth) {
  1023. $indent = str_repeat("\t", $depth);
  1024. $output .= "$indent</ul>\n";
  1025. }
  1026. /**
  1027. * @see Walker::start_el()
  1028. * @since 2.1.0
  1029. *
  1030. * @param string $output Passed by reference. Used to append additional content.
  1031. * @param object $page Page data object.
  1032. * @param int $depth Depth of page. Used for padding.
  1033. * @param int $current_page Page ID.
  1034. * @param array $args
  1035. */
  1036. function start_el(&$output, $page, $depth, $args, $current_page) {
  1037. if ( $depth )
  1038. $indent = str_repeat("\t", $depth);
  1039. else
  1040. $indent = '';
  1041. extract($args, EXTR_SKIP);
  1042. $css_class = array('page_item', 'page-item-'.$page->ID);
  1043. if ( !empty($current_page) ) {
  1044. $_current_page = get_page( $current_page );
  1045. if ( isset($_current_page->ancestors) && in_array($page->ID, (array) $_current_page->ancestors) )
  1046. $css_class[] = 'current_page_ancestor';
  1047. if ( $page->ID == $current_page )
  1048. $css_class[] = 'current_page_item';
  1049. elseif ( $_current_page && $page->ID == $_current_page->post_parent )
  1050. $css_class[] = 'current_page_parent';
  1051. } elseif ( $page->ID == get_option('page_for_posts') ) {
  1052. $css_class[] = 'current_page_parent';
  1053. }
  1054. $css_class = implode(' ', apply_filters('page_css_class', $css_class, $page));
  1055. $output .= $indent . '<li class="' . $css_class . '"><a href="' . get_page_link($page->ID) . '" title="' . esc_attr( wp_strip_all_tags( apply_filters( 'the_title', $page->post_title, $page->ID ) ) ) . '">' . $link_before . apply_filters( 'the_title', $page->post_title, $page->ID ) . $link_after . '</a>';
  1056. if ( !empty($show_date) ) {
  1057. if ( 'modified' == $show_date )
  1058. $time = $page->post_modified;
  1059. else
  1060. $time = $page->post_date;
  1061. $output .= " " . mysql2date($date_format, $time);
  1062. }
  1063. }
  1064. /**
  1065. * @see Walker::end_el()
  1066. * @since 2.1.0
  1067. *
  1068. * @param string $output Passed by reference. Used to append additional content.
  1069. * @param object $page Page data object. Not used.
  1070. * @param int $depth Depth of page. Not Used.
  1071. */
  1072. function end_el(&$output, $page, $depth) {
  1073. $output .= "</li>\n";
  1074. }
  1075. }
  1076. /**
  1077. * Create HTML dropdown list of pages.
  1078. *
  1079. * @package WordPress
  1080. * @since 2.1.0
  1081. * @uses Walker
  1082. */
  1083. class Walker_PageDropdown extends Walker {
  1084. /**
  1085. * @see Walker::$tree_type
  1086. * @since 2.1.0
  1087. * @var string
  1088. */
  1089. var $tree_type = 'page';
  1090. /**
  1091. * @see Walker::$db_fields
  1092. * @since 2.1.0
  1093. * @todo Decouple this
  1094. * @var array
  1095. */
  1096. var $db_fields = array ('parent' => 'post_parent', 'id' => 'ID');
  1097. /**
  1098. * @see Walker::start_el()
  1099. * @since 2.1.0
  1100. *
  1101. * @param string $output Passed by reference. Used to append additional content.
  1102. * @param object $page Page data object.
  1103. * @param int $depth Depth of page in reference to parent pages. Used for padding.
  1104. * @param array $args Uses 'selected' argument for selected page to set selected HTML attribute for option element.
  1105. */
  1106. function start_el(&$output, $page, $depth, $args) {
  1107. $pad = str_repeat('&nbsp;', $depth * 3);
  1108. $output .= "\t<option class=\"level-$depth\" value=\"$page->ID\"";
  1109. if ( $page->ID == $args['selected'] )
  1110. $output .= ' selected="selected"';
  1111. $output .= '>';
  1112. $title = esc_html($page->post_title);
  1113. $output .= "$pad$title";
  1114. $output .= "</option>\n";
  1115. }
  1116. }
  1117. /**
  1118. * Create HTML list of categories.
  1119. *
  1120. * @package WordPress
  1121. * @since 2.1.0
  1122. * @uses Walker
  1123. */
  1124. class Walker_Category extends Walker {
  1125. /**
  1126. * @see Walker::$tree_type
  1127. * @since 2.1.0
  1128. * @var string
  1129. */
  1130. var $tree_type = 'category';
  1131. /**
  1132. * @see Walker::$db_fields
  1133. * @since 2.1.0
  1134. * @todo Decouple this
  1135. * @var array
  1136. */
  1137. var $db_fields = array ('parent' => 'parent', 'id' => 'term_id');
  1138. /**
  1139. * @see Walker::start_lvl()
  1140. * @since 2.1.0
  1141. *
  1142. * @param string $output Passed by reference. Used to append additional content.
  1143. * @param int $depth Depth of category. Used for tab indentation.
  1144. * @param array $args Will only append content if style argument value is 'list'.
  1145. */
  1146. function start_lvl(&$output, $depth, $args) {
  1147. if ( 'list' != $args['style'] )
  1148. return;
  1149. $indent = str_repeat("\t", $depth);
  1150. $output .= "$indent<ul class='children'>\n";
  1151. }
  1152. /**
  1153. * @see Walker::end_lvl()
  1154. * @since 2.1.0
  1155. *
  1156. * @param string $output Passed by reference. Used to append additional content.
  1157. * @param int $depth Depth of category. Used for tab indentation.
  1158. * @param array $args Will only append content if style argument value is 'list'.
  1159. */
  1160. function end_lvl(&$output, $depth, $args) {
  1161. if ( 'list' != $args['style'] )
  1162. return;
  1163. $indent = str_repeat("\t", $depth);
  1164. $output .= "$indent</ul>\n";
  1165. }
  1166. /**
  1167. * @see Walker::start_el()
  1168. * @since 2.1.0
  1169. *
  1170. * @param string $output Passed by reference. Used to append additional content.
  1171. * @param object $category Category data object.
  1172. * @param int $depth Depth of category in reference to parents.
  1173. * @param array $args
  1174. */
  1175. function start_el(&$output, $category, $depth, $args) {
  1176. extract($args);
  1177. $cat_name = esc_attr( $category->name);
  1178. $cat_name = apply_filters( 'list_cats', $cat_name, $category );
  1179. $link = '<a href="' . get_term_link( $category, $category->taxonomy ) . '" ';
  1180. if ( $use_desc_for_title == 0 || empty($category->description) )
  1181. $link .= 'title="' . sprintf(__( 'View all posts filed under %s' ), $cat_name) . '"';
  1182. else
  1183. $link .= 'title="' . esc_attr( strip_tags( apply_filters( 'category_description', $category->description, $category ) ) ) . '"';
  1184. $link .= '>';
  1185. $link .= $cat_name . '</a>';
  1186. if ( (! empty($feed_image)) || (! empty($feed)) ) {
  1187. $link .= ' ';
  1188. if ( empty($feed_image) )
  1189. $link .= '(';
  1190. $link .= '<a href="' . get_term_feed_link( $category->term_id, $category->taxonomy, $feed_type ) . '"';
  1191. if ( empty($feed) )
  1192. $alt = ' alt="' . sprintf(__( 'Feed for all posts filed under %s' ), $cat_name ) . '"';
  1193. else {
  1194. $title = ' title="' . $feed . '"';
  1195. $alt = ' alt="' . $feed . '"';
  1196. $name = $feed;
  1197. $link .= $title;
  1198. }
  1199. $link .= '>';
  1200. if ( empty($feed_image) )
  1201. $link .= $name;
  1202. else
  1203. $link .= "<img src='$feed_image'$alt$title" . ' />';
  1204. $link .= '</a>';
  1205. if ( empty($feed_image) )
  1206. $link .= ')';
  1207. }
  1208. if ( isset($show_count) && $show_count )
  1209. $link .= ' (' . intval($category->count) . ')';
  1210. if ( isset($show_date) && $show_date ) {
  1211. $link .= ' ' . gmdate('Y-m-d', $category->last_update_timestamp);
  1212. }
  1213. if ( isset($current_category) && $current_category )
  1214. $_current_category = get_category( $current_category );
  1215. if ( 'list' == $args['style'] ) {
  1216. $output .= "\t<li";
  1217. $class = 'cat-item cat-item-'.$category->term_id;
  1218. if ( isset($current_category) && $current_category && ($category->term_id == $current_category) )
  1219. $class .= ' current-cat';
  1220. elseif ( isset($_current_category) && $_current_category && ($category->term_id == $_current_category->parent) )
  1221. $class .= ' current-cat-parent';
  1222. $output .= ' class="'.$class.'"';
  1223. $output .= ">$link\n";
  1224. } else {
  1225. $output .= "\t$link<br />\n";
  1226. }
  1227. }
  1228. /**
  1229. * @see Walker::end_el()
  1230. * @since 2.1.0
  1231. *
  1232. * @param string $output Passed by reference. Used to append additional content.
  1233. * @param object $page Not used.
  1234. * @param int $depth Depth of category. Not used.
  1235. * @param array $args Only uses 'list' for whether should append to output.
  1236. */
  1237. function end_el(&$output, $page, $depth, $args) {
  1238. if ( 'list' != $args['style'] )
  1239. return;
  1240. $output .= "</li>\n";
  1241. }
  1242. }
  1243. /**
  1244. * Create HTML dropdown list of Categories.
  1245. *
  1246. * @package WordPress
  1247. * @since 2.1.0
  1248. * @uses Walker
  1249. */
  1250. class Walker_CategoryDropdown extends Walker {
  1251. /**
  1252. * @see Walker::$tree_type
  1253. * @since 2.1.0
  1254. * @var string
  1255. */
  1256. var $tree_type = 'category';
  1257. /**
  1258. * @see Walker::$db_fields
  1259. * @since 2.1.0
  1260. * @todo Decouple this
  1261. * @var array
  1262. */
  1263. var $db_fields = array ('parent' => 'parent', 'id' => 'term_id');
  1264. /**
  1265. * @see Walker::start_el()
  1266. * @since 2.1.0
  1267. *
  1268. * @param string $output Passed by reference. Used to append additional content.
  1269. * @param object $category Category data object.
  1270. * @param int $depth Depth of category. Used for padding.
  1271. * @param array $args Uses 'selected', 'show_count', and 'show_last_update' keys, if they exist.
  1272. */
  1273. function start_el(&$output, $category, $depth, $args) {
  1274. $pad = str_repeat('&nbsp;', $depth * 3);
  1275. $cat_name = apply_filters('list_cats', $category->name, $category);
  1276. $output .= "\t<option class=\"level-$depth\" value=\"".$category->term_id."\"";
  1277. if ( $category->term_id == $args['selected'] )
  1278. $output .= ' selected="selected"';
  1279. $output .= '>';
  1280. $output .= $pad.$cat_name;
  1281. if ( $args['show_count'] )
  1282. $output .= '&nbsp;&nbsp;('. $category->count .')';
  1283. if ( $args['show_last_update'] ) {
  1284. $format = 'Y-m-d';
  1285. $output .= '&nbsp;&nbsp;' . gmdate($format, $category->last_update_timestamp);
  1286. }
  1287. $output .= "</option>\n";
  1288. }
  1289. }
  1290. /**
  1291. * Send XML response back to AJAX request.
  1292. *
  1293. * @package WordPress
  1294. * @since 2.1.0
  1295. */
  1296. class WP_Ajax_Response {
  1297. /**
  1298. * Store XML responses to send.
  1299. *
  1300. * @since 2.1.0
  1301. * @var array
  1302. * @access private
  1303. */
  1304. var $responses = array();
  1305. /**
  1306. * PHP4 Constructor - Passes args to {@link WP_Ajax_Response::add()}.
  1307. *
  1308. * @since 2.1.0
  1309. * @see WP_Ajax_Response::add()
  1310. *
  1311. * @param string|array $args Optional. Will be passed to add() method.
  1312. * @return WP_Ajax_Response
  1313. */
  1314. function WP_Ajax_Response( $args = '' ) {
  1315. if ( !empty($args) )
  1316. $this->add($args);
  1317. }
  1318. /**
  1319. * Append to XML response based on given arguments.
  1320. *
  1321. * The arguments that can be passed in the $args parameter are below. It is
  1322. * also possible to pass a WP_Error object in either the 'id' or 'data'
  1323. * argument. The parameter isn't actually optional, content should be given
  1324. * in order to send the correct response.
  1325. *
  1326. * 'what' argument is a string that is the XMLRPC response type.
  1327. * 'action' argument is a boolean or string that acts like a nonce.
  1328. * 'id' argument can be WP_Error or an integer.
  1329. * 'old_id' argument is false by default or an integer of the previous ID.
  1330. * 'position' argument is an integer or a string with -1 = top, 1 = bottom,
  1331. * html ID = after, -html ID = before.
  1332. * 'data' argument is a string with the content or message.
  1333. * 'supplemental' argument is an array of strings that will be children of
  1334. * the supplemental element.
  1335. *
  1336. * @since 2.1.0
  1337. *
  1338. * @param string|array $args Override defaults.
  1339. * @return string XML response.
  1340. */
  1341. function add( $args = '' ) {
  1342. $defaults = array(
  1343. 'what' => 'object', 'action' => false,
  1344. 'id' => '0', 'old_id' => false,
  1345. 'position' => 1,
  1346. 'data' => '', 'supplemental' => array()
  1347. );
  1348. $r = wp_parse_args( $args, $defaults );
  1349. extract( $r, EXTR_SKIP );
  1350. $position = preg_replace( '/[^a-z0-9:_-]/i', '', $position );
  1351. if ( is_wp_error($id) ) {
  1352. $data = $id;
  1353. $id = 0;
  1354. }
  1355. $response = '';
  1356. if ( is_wp_error($data) ) {
  1357. foreach ( (array) $data->get_error_codes() as $code ) {
  1358. $response .= "<wp_error code='$code'><![CDATA[" . $data->get_error_message($code) . "]]></wp_error>";
  1359. if ( !$error_data = $data->get_error_data($code) )
  1360. continue;
  1361. $class = '';
  1362. if ( is_object($error_data) ) {
  1363. $class = ' class="' . get_class($error_data) . '"';
  1364. $error_data = get_object_vars($error_data);
  1365. }
  1366. $response .= "<wp_error_data code='$code'$class>";
  1367. if ( is_scalar($error_data) ) {
  1368. $response .= "<![CDATA[$error_data]]>";
  1369. } elseif ( is_array($error_data) ) {
  1370. foreach ( $error_data as $k => $v )
  1371. $response .= "<$k><![CDATA[$v]]></$k>";
  1372. }
  1373. $response .= "</wp_error_data>";
  1374. }
  1375. } else {
  1376. $response = "<response_data><![CDATA[$data]]></response_data>";
  1377. }
  1378. $s = '';
  1379. if ( is_array($supplemental) ) {
  1380. foreach ( $supplemental as $k => $v )
  1381. $s .= "<$k><![CDATA[$v]]></$k>";
  1382. $s = "<supplemental>$s</supplemental>";
  1383. }
  1384. if ( false === $action )
  1385. $action = $_POST['action'];
  1386. $x = '';
  1387. $x .= "<response action='{$action}_$id'>"; // The action attribute in the xml output is formatted like a nonce action
  1388. $x .= "<$what id='$id' " . ( false === $old_id ? '' : "old_id='$old_id' " ) . "position='$position'>";
  1389. $x .= $response;
  1390. $x .= $s;
  1391. $x .= "</$what>";
  1392. $x .= "</response>";
  1393. $this->responses[] = $x;
  1394. return $x;
  1395. }
  1396. /**
  1397. * Display XML formatted responses.
  1398. *
  1399. * Sets the content type header to text/xml.
  1400. *
  1401. * @since 2.1.0
  1402. */
  1403. function send() {
  1404. header('Content-Type: text/xml');
  1405. echo "<?xml version='1.0' standalone='yes'?><wp_ajax>";
  1406. foreach ( (array) $this->responses as $response )
  1407. echo $response;
  1408. echo '</wp_ajax>';
  1409. die();
  1410. }
  1411. }
  1412. /**
  1413. * Helper class to remove the need to use eval to replace $matches[] in query strings.
  1414. *
  1415. * @since 2.9.0
  1416. */
  1417. class WP_MatchesMapRegex {
  1418. /**
  1419. * store for matches
  1420. *
  1421. * @access private
  1422. * @var array
  1423. */
  1424. var $_matches;
  1425. /**
  1426. * store for mapping result
  1427. *
  1428. * @access public
  1429. * @var string
  1430. */
  1431. var $output;
  1432. /**
  1433. * subject to perform mapping on (query string containing $matches[] references
  1434. *
  1435. * @access private
  1436. * @var string
  1437. */
  1438. var $_subject;
  1439. /**
  1440. * regexp pattern to match $matches[] references
  1441. *
  1442. * @var string
  1443. */
  1444. var $_pattern = '(\$matches\[[1-9]+[0-9]*\])'; // magic number
  1445. /**
  1446. * constructor
  1447. *
  1448. * @param string $subject subject if regex
  1449. * @param array $matches data to use in map
  1450. * @return self
  1451. */
  1452. function WP_MatchesMapRegex($subject, $matches) {
  1453. $this->_subject = $subject;
  1454. $this->_matches = $matches;
  1455. $this->output = $this->_map();
  1456. }
  1457. /**
  1458. * Substitute substring matches in subject.
  1459. *
  1460. * static helper function to ease use
  1461. *
  1462. * @access public
  1463. * @param string $subject subject
  1464. * @param array $matches data used for subsitution
  1465. * @return string
  1466. */
  1467. function apply($subject, $matches) {
  1468. $oSelf =& new WP_MatchesMapRegex($subject, $matches);
  1469. return $oSelf->output;
  1470. }
  1471. /**
  1472. * do the actual mapping
  1473. *
  1474. * @access private
  1475. * @return string
  1476. */
  1477. function _map() {
  1478. $callback = array(&$this, 'callback');
  1479. return preg_replace_callback($this->_pattern, $callback, $this->_subject);
  1480. }
  1481. /**
  1482. * preg_replace_callback hook
  1483. *
  1484. * @access public
  1485. * @param array $matches preg_replace regexp matches
  1486. * @return string
  1487. */
  1488. function callback($matches) {
  1489. $index = intval(substr($matches[0], 9, -1));
  1490. return ( isset( $this->_matches[$index] ) ? urlencode($this->_matches[$index]) : '' );
  1491. }
  1492. }
  1493. ?>