[ Index ]

PHP Cross Reference of Wordpress 2.9.1

title

Body

[close]

/wp-includes/ -> classes.php (source)

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


Generated: Fri Jan 8 00:19:48 2010 Cross-referenced by PHPXref 0.7