-
+ 42A3D6BAF466D997F62B27BD07F1DCE43B164E39091CB05CFC9ECF20E5DA094EBF46F4F297DA4040E2B3DF352CA36D45537EB7F5BAA96758CB3773A7E9D40BD7
mp-wp/wp-includes/classes.php
(0 . 0)(1 . 1583)
81950 <?php
81951 /**
81952 * Holds Most of the WordPress classes.
81953 *
81954 * Some of the other classes are contained in other files. For example, the
81955 * WordPress cache is in cache.php and the WordPress roles API is in
81956 * capabilities.php. The third party libraries are contained in their own
81957 * separate files.
81958 *
81959 * @package WordPress
81960 */
81961
81962 /**
81963 * WordPress environment setup class.
81964 *
81965 * @package WordPress
81966 * @since 2.0.0
81967 */
81968 class WP {
81969 /**
81970 * Public query variables.
81971 *
81972 * Long list of public query variables.
81973 *
81974 * @since 2.0.0
81975 * @access public
81976 * @var array
81977 */
81978 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');
81979
81980 /**
81981 * Private query variables.
81982 *
81983 * Long list of private query variables.
81984 *
81985 * @since 2.0.0
81986 * @var array
81987 */
81988 var $private_query_vars = array('offset', 'posts_per_page', 'posts_per_archive_page', 'what_to_show', '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');
81989
81990 /**
81991 * Extra query variables set by the user.
81992 *
81993 * @since 2.1.0
81994 * @var array
81995 */
81996 var $extra_query_vars = array();
81997
81998 /**
81999 * Query variables for setting up the WordPress Query Loop.
82000 *
82001 * @since 2.0.0
82002 * @var array
82003 */
82004 var $query_vars;
82005
82006 /**
82007 * String parsed to set the query variables.
82008 *
82009 * @since 2.0.0
82010 * @var string
82011 */
82012 var $query_string;
82013
82014 /**
82015 * Permalink or requested URI.
82016 *
82017 * @since 2.0.0
82018 * @var string
82019 */
82020 var $request;
82021
82022 /**
82023 * Rewrite rule the request matched.
82024 *
82025 * @since 2.0.0
82026 * @var string
82027 */
82028 var $matched_rule;
82029
82030 /**
82031 * Rewrite query the request matched.
82032 *
82033 * @since 2.0.0
82034 * @var string
82035 */
82036 var $matched_query;
82037
82038 /**
82039 * Whether already did the permalink.
82040 *
82041 * @since 2.0.0
82042 * @var bool
82043 */
82044 var $did_permalink = false;
82045
82046 /**
82047 * Add name to list of public query variables.
82048 *
82049 * @since 2.1.0
82050 *
82051 * @param string $qv Query variable name.
82052 */
82053 function add_query_var($qv) {
82054 if ( !in_array($qv, $this->public_query_vars) )
82055 $this->public_query_vars[] = $qv;
82056 }
82057
82058 /**
82059 * Set the value of a query variable.
82060 *
82061 * @since 2.3.0
82062 *
82063 * @param string $key Query variable name.
82064 * @param mixed $value Query variable value.
82065 */
82066 function set_query_var($key, $value) {
82067 $this->query_vars[$key] = $value;
82068 }
82069
82070 /**
82071 * Parse request to find correct WordPress query.
82072 *
82073 * Sets up the query variables based on the request. There are also many
82074 * filters and actions that can be used to further manipulate the result.
82075 *
82076 * @since 2.0.0
82077 *
82078 * @param array|string $extra_query_vars Set the extra query variables.
82079 */
82080 function parse_request($extra_query_vars = '') {
82081 global $wp_rewrite;
82082
82083 $this->query_vars = array();
82084 $taxonomy_query_vars = array();
82085
82086 if ( is_array($extra_query_vars) )
82087 $this->extra_query_vars = & $extra_query_vars;
82088 else if (! empty($extra_query_vars))
82089 parse_str($extra_query_vars, $this->extra_query_vars);
82090
82091 // Process PATH_INFO, REQUEST_URI, and 404 for permalinks.
82092
82093 // Fetch the rewrite rules.
82094 $rewrite = $wp_rewrite->wp_rewrite_rules();
82095
82096 if (! empty($rewrite)) {
82097 // If we match a rewrite rule, this will be cleared.
82098 $error = '404';
82099 $this->did_permalink = true;
82100
82101 if ( isset($_SERVER['PATH_INFO']) )
82102 $pathinfo = $_SERVER['PATH_INFO'];
82103 else
82104 $pathinfo = '';
82105 $pathinfo_array = explode('?', $pathinfo);
82106 $pathinfo = str_replace("%", "%25", $pathinfo_array[0]);
82107 $req_uri = $_SERVER['REQUEST_URI'];
82108 $req_uri_array = explode('?', $req_uri);
82109 $req_uri = $req_uri_array[0];
82110 $self = $_SERVER['PHP_SELF'];
82111 $home_path = parse_url(get_option('home'));
82112 if ( isset($home_path['path']) )
82113 $home_path = $home_path['path'];
82114 else
82115 $home_path = '';
82116 $home_path = trim($home_path, '/');
82117
82118 // Trim path info from the end and the leading home path from the
82119 // front. For path info requests, this leaves us with the requesting
82120 // filename, if any. For 404 requests, this leaves us with the
82121 // requested permalink.
82122 $req_uri = str_replace($pathinfo, '', rawurldecode($req_uri));
82123 $req_uri = trim($req_uri, '/');
82124 $req_uri = preg_replace("|^$home_path|", '', $req_uri);
82125 $req_uri = trim($req_uri, '/');
82126 $pathinfo = trim($pathinfo, '/');
82127 $pathinfo = preg_replace("|^$home_path|", '', $pathinfo);
82128 $pathinfo = trim($pathinfo, '/');
82129 $self = trim($self, '/');
82130 $self = preg_replace("|^$home_path|", '', $self);
82131 $self = trim($self, '/');
82132
82133 // The requested permalink is in $pathinfo for path info requests and
82134 // $req_uri for other requests.
82135 if ( ! empty($pathinfo) && !preg_match('|^.*' . $wp_rewrite->index . '$|', $pathinfo) ) {
82136 $request = $pathinfo;
82137 } else {
82138 // If the request uri is the index, blank it out so that we don't try to match it against a rule.
82139 if ( $req_uri == $wp_rewrite->index )
82140 $req_uri = '';
82141 $request = $req_uri;
82142 }
82143
82144 $this->request = $request;
82145
82146 // Look for matches.
82147 $request_match = $request;
82148 foreach ( (array) $rewrite as $match => $query) {
82149 // Don't try to match against AtomPub calls
82150 if ( $req_uri == 'wp-app.php' )
82151 break;
82152
82153 // If the requesting file is the anchor of the match, prepend it
82154 // to the path info.
82155 if ((! empty($req_uri)) && (strpos($match, $req_uri) === 0) && ($req_uri != $request)) {
82156 $request_match = $req_uri . '/' . $request;
82157 }
82158
82159 if (preg_match("!^$match!", $request_match, $matches) ||
82160 preg_match("!^$match!", urldecode($request_match), $matches)) {
82161 // Got a match.
82162 $this->matched_rule = $match;
82163
82164 // Trim the query of everything up to the '?'.
82165 $query = preg_replace("!^.+\?!", '', $query);
82166
82167 // Substitute the substring matches into the query.
82168 eval("@\$query = \"" . addslashes($query) . "\";");
82169
82170 $this->matched_query = $query;
82171
82172 // Parse the query.
82173 parse_str($query, $perma_query_vars);
82174
82175 // If we're processing a 404 request, clear the error var
82176 // since we found something.
82177 if (isset($_GET['error']))
82178 unset($_GET['error']);
82179
82180 if (isset($error))
82181 unset($error);
82182
82183 break;
82184 }
82185 }
82186
82187 // If req_uri is empty or if it is a request for ourself, unset error.
82188 if (empty($request) || $req_uri == $self || strpos($_SERVER['PHP_SELF'], 'wp-admin/') !== false) {
82189 if (isset($_GET['error']))
82190 unset($_GET['error']);
82191
82192 if (isset($error))
82193 unset($error);
82194
82195 if (isset($perma_query_vars) && strpos($_SERVER['PHP_SELF'], 'wp-admin/') !== false)
82196 unset($perma_query_vars);
82197
82198 $this->did_permalink = false;
82199 }
82200 }
82201
82202 $this->public_query_vars = apply_filters('query_vars', $this->public_query_vars);
82203
82204 foreach ( $GLOBALS['wp_taxonomies'] as $taxonomy => $t )
82205 if ( isset($t->query_var) )
82206 $taxonomy_query_vars[$t->query_var] = $taxonomy;
82207
82208 for ($i=0; $i<count($this->public_query_vars); $i += 1) {
82209 $wpvar = $this->public_query_vars[$i];
82210 if (isset($this->extra_query_vars[$wpvar]))
82211 $this->query_vars[$wpvar] = $this->extra_query_vars[$wpvar];
82212 elseif (isset($GLOBALS[$wpvar]))
82213 $this->query_vars[$wpvar] = $GLOBALS[$wpvar];
82214 elseif (!empty($_POST[$wpvar]))
82215 $this->query_vars[$wpvar] = $_POST[$wpvar];
82216 elseif (!empty($_GET[$wpvar]))
82217 $this->query_vars[$wpvar] = $_GET[$wpvar];
82218 elseif (!empty($perma_query_vars[$wpvar]))
82219 $this->query_vars[$wpvar] = $perma_query_vars[$wpvar];
82220
82221 if ( !empty( $this->query_vars[$wpvar] ) ) {
82222 $this->query_vars[$wpvar] = (string) $this->query_vars[$wpvar];
82223 if ( in_array( $wpvar, $taxonomy_query_vars ) ) {
82224 $this->query_vars['taxonomy'] = $taxonomy_query_vars[$wpvar];
82225 $this->query_vars['term'] = $this->query_vars[$wpvar];
82226 }
82227 }
82228 }
82229
82230 foreach ( (array) $this->private_query_vars as $var) {
82231 if (isset($this->extra_query_vars[$var]))
82232 $this->query_vars[$var] = $this->extra_query_vars[$var];
82233 elseif (isset($GLOBALS[$var]) && '' != $GLOBALS[$var])
82234 $this->query_vars[$var] = $GLOBALS[$var];
82235 }
82236
82237 if ( isset($error) )
82238 $this->query_vars['error'] = $error;
82239
82240 $this->query_vars = apply_filters('request', $this->query_vars);
82241
82242 do_action_ref_array('parse_request', array(&$this));
82243 }
82244
82245 /**
82246 * Send additional HTTP headers for caching, content type, etc.
82247 *
82248 * Sets the X-Pingback header, 404 status (if 404), Content-type. If showing
82249 * a feed, it will also send last-modified, etag, and 304 status if needed.
82250 *
82251 * @since 2.0.0
82252 */
82253 function send_headers() {
82254 @header('X-Pingback: '. get_bloginfo('pingback_url'));
82255 if ( is_user_logged_in() )
82256 nocache_headers();
82257 if ( !empty($this->query_vars['error']) && '404' == $this->query_vars['error'] ) {
82258 status_header( 404 );
82259 if ( !is_user_logged_in() )
82260 nocache_headers();
82261 @header('Content-Type: ' . get_option('html_type') . '; charset=' . get_option('blog_charset'));
82262 } else if ( empty($this->query_vars['feed']) ) {
82263 @header('Content-Type: ' . get_option('html_type') . '; charset=' . get_option('blog_charset'));
82264 } else {
82265 // We're showing a feed, so WP is indeed the only thing that last changed
82266 if ( !empty($this->query_vars['withcomments'])
82267 || ( empty($this->query_vars['withoutcomments'])
82268 && ( !empty($this->query_vars['p'])
82269 || !empty($this->query_vars['name'])
82270 || !empty($this->query_vars['page_id'])
82271 || !empty($this->query_vars['pagename'])
82272 || !empty($this->query_vars['attachment'])
82273 || !empty($this->query_vars['attachment_id'])
82274 )
82275 )
82276 )
82277 $wp_last_modified = mysql2date('D, d M Y H:i:s', get_lastcommentmodified('GMT'), 0).' GMT';
82278 else
82279 $wp_last_modified = mysql2date('D, d M Y H:i:s', get_lastpostmodified('GMT'), 0).' GMT';
82280 $wp_etag = '"' . md5($wp_last_modified) . '"';
82281 @header("Last-Modified: $wp_last_modified");
82282 @header("ETag: $wp_etag");
82283
82284 // Support for Conditional GET
82285 if (isset($_SERVER['HTTP_IF_NONE_MATCH']))
82286 $client_etag = stripslashes(stripslashes($_SERVER['HTTP_IF_NONE_MATCH']));
82287 else $client_etag = false;
82288
82289 $client_last_modified = empty($_SERVER['HTTP_IF_MODIFIED_SINCE']) ? '' : trim($_SERVER['HTTP_IF_MODIFIED_SINCE']);
82290 // If string is empty, return 0. If not, attempt to parse into a timestamp
82291 $client_modified_timestamp = $client_last_modified ? strtotime($client_last_modified) : 0;
82292
82293 // Make a timestamp for our most recent modification...
82294 $wp_modified_timestamp = strtotime($wp_last_modified);
82295
82296 if ( ($client_last_modified && $client_etag) ?
82297 (($client_modified_timestamp >= $wp_modified_timestamp) && ($client_etag == $wp_etag)) :
82298 (($client_modified_timestamp >= $wp_modified_timestamp) || ($client_etag == $wp_etag)) ) {
82299 status_header( 304 );
82300 exit;
82301 }
82302 }
82303
82304 do_action_ref_array('send_headers', array(&$this));
82305 }
82306
82307 /**
82308 * Sets the query string property based off of the query variable property.
82309 *
82310 * The 'query_string' filter is deprecated, but still works. Plugins should
82311 * use the 'request' filter instead.
82312 *
82313 * @since 2.0.0
82314 */
82315 function build_query_string() {
82316 $this->query_string = '';
82317 foreach ( (array) array_keys($this->query_vars) as $wpvar) {
82318 if ( '' != $this->query_vars[$wpvar] ) {
82319 $this->query_string .= (strlen($this->query_string) < 1) ? '' : '&';
82320 if ( !is_scalar($this->query_vars[$wpvar]) ) // Discard non-scalars.
82321 continue;
82322 $this->query_string .= $wpvar . '=' . rawurlencode($this->query_vars[$wpvar]);
82323 }
82324 }
82325
82326 // query_string filter deprecated. Use request filter instead.
82327 if ( has_filter('query_string') ) { // Don't bother filtering and parsing if no plugins are hooked in.
82328 $this->query_string = apply_filters('query_string', $this->query_string);
82329 parse_str($this->query_string, $this->query_vars);
82330 }
82331 }
82332
82333 /**
82334 * Setup the WordPress Globals.
82335 *
82336 * The query_vars property will be extracted to the GLOBALS. So care should
82337 * be taken when naming global variables that might interfere with the
82338 * WordPress environment.
82339 *
82340 * @global string $query_string Query string for the loop.
82341 * @global int $more Only set, if single page or post.
82342 * @global int $single If single page or post. Only set, if single page or post.
82343 *
82344 * @since 2.0.0
82345 */
82346 function register_globals() {
82347 global $wp_query;
82348 // Extract updated query vars back into global namespace.
82349 foreach ( (array) $wp_query->query_vars as $key => $value) {
82350 $GLOBALS[$key] = $value;
82351 }
82352
82353 $GLOBALS['query_string'] = & $this->query_string;
82354 $GLOBALS['posts'] = & $wp_query->posts;
82355 $GLOBALS['post'] = & $wp_query->post;
82356 $GLOBALS['request'] = & $wp_query->request;
82357
82358 if ( is_single() || is_page() ) {
82359 $GLOBALS['more'] = 1;
82360 $GLOBALS['single'] = 1;
82361 }
82362 }
82363
82364 /**
82365 * Setup the current user.
82366 *
82367 * @since 2.0.0
82368 */
82369 function init() {
82370 wp_get_current_user();
82371 }
82372
82373 /**
82374 * Setup the Loop based on the query variables.
82375 *
82376 * @uses WP::$query_vars
82377 * @since 2.0.0
82378 */
82379 function query_posts() {
82380 global $wp_the_query;
82381 $this->build_query_string();
82382 $wp_the_query->query($this->query_vars);
82383 }
82384
82385 /**
82386 * Set the Headers for 404, if permalink is not found.
82387 *
82388 * Issue a 404 if a permalink request doesn't match any posts. Don't issue
82389 * a 404 if one was already issued, if the request was a search, or if the
82390 * request was a regular query string request rather than a permalink
82391 * request. Issues a 200, if not 404.
82392 *
82393 * @since 2.0.0
82394 */
82395 function handle_404() {
82396 global $wp_query;
82397
82398 if ( (0 == count($wp_query->posts)) && !is_404() && !is_search() && ( $this->did_permalink || (!empty($_SERVER['QUERY_STRING']) && (false === strpos($_SERVER['REQUEST_URI'], '?'))) ) ) {
82399 // Don't 404 for these queries if they matched an object.
82400 if ( ( is_tag() || is_category() || is_author() ) && $wp_query->get_queried_object() ) {
82401 if ( !is_404() )
82402 status_header( 200 );
82403 return;
82404 }
82405 $wp_query->set_404();
82406 status_header( 404 );
82407 nocache_headers();
82408 } elseif ( !is_404() ) {
82409 status_header( 200 );
82410 }
82411 }
82412
82413 /**
82414 * Sets up all of the variables required by the WordPress environment.
82415 *
82416 * The action 'wp' has one parameter that references the WP object. It
82417 * allows for accessing the properties and methods to further manipulate the
82418 * object.
82419 *
82420 * @since 2.0.0
82421 *
82422 * @param string|array $query_args Passed to {@link parse_request()}
82423 */
82424 function main($query_args = '') {
82425 $this->init();
82426 $this->parse_request($query_args);
82427 $this->send_headers();
82428 $this->query_posts();
82429 $this->handle_404();
82430 $this->register_globals();
82431 do_action_ref_array('wp', array(&$this));
82432 }
82433
82434 /**
82435 * PHP4 Constructor - Does nothing.
82436 *
82437 * Call main() method when ready to run setup.
82438 *
82439 * @since 2.0.0
82440 *
82441 * @return WP
82442 */
82443 function WP() {
82444 // Empty.
82445 }
82446 }
82447
82448 /**
82449 * WordPress Error class.
82450 *
82451 * Container for checking for WordPress errors and error messages. Return
82452 * WP_Error and use {@link is_wp_error()} to check if this class is returned.
82453 * Many core WordPress functions pass this class in the event of an error and
82454 * if not handled properly will result in code errors.
82455 *
82456 * @package WordPress
82457 * @since 2.1.0
82458 */
82459 class WP_Error {
82460 /**
82461 * Stores the list of errors.
82462 *
82463 * @since 2.1.0
82464 * @var array
82465 * @access private
82466 */
82467 var $errors = array();
82468
82469 /**
82470 * Stores the list of data for error codes.
82471 *
82472 * @since 2.1.0
82473 * @var array
82474 * @access private
82475 */
82476 var $error_data = array();
82477
82478 /**
82479 * PHP4 Constructor - Sets up error message.
82480 *
82481 * If code parameter is empty then nothing will be done. It is possible to
82482 * add multiple messages to the same code, but with other methods in the
82483 * class.
82484 *
82485 * All parameters are optional, but if the code parameter is set, then the
82486 * data parameter is optional.
82487 *
82488 * @since 2.1.0
82489 *
82490 * @param string|int $code Error code
82491 * @param string $message Error message
82492 * @param mixed $data Optional. Error data.
82493 * @return WP_Error
82494 */
82495 function WP_Error($code = '', $message = '', $data = '') {
82496 if ( empty($code) )
82497 return;
82498
82499 $this->errors[$code][] = $message;
82500
82501 if ( ! empty($data) )
82502 $this->error_data[$code] = $data;
82503 }
82504
82505 /**
82506 * Retrieve all error codes.
82507 *
82508 * @since 2.1.0
82509 * @access public
82510 *
82511 * @return array List of error codes, if avaiable.
82512 */
82513 function get_error_codes() {
82514 if ( empty($this->errors) )
82515 return array();
82516
82517 return array_keys($this->errors);
82518 }
82519
82520 /**
82521 * Retrieve first error code available.
82522 *
82523 * @since 2.1.0
82524 * @access public
82525 *
82526 * @return string|int Empty string, if no error codes.
82527 */
82528 function get_error_code() {
82529 $codes = $this->get_error_codes();
82530
82531 if ( empty($codes) )
82532 return '';
82533
82534 return $codes[0];
82535 }
82536
82537 /**
82538 * Retrieve all error messages or error messages matching code.
82539 *
82540 * @since 2.1.0
82541 *
82542 * @param string|int $code Optional. Retrieve messages matching code, if exists.
82543 * @return array Error strings on success, or empty array on failure (if using codee parameter).
82544 */
82545 function get_error_messages($code = '') {
82546 // Return all messages if no code specified.
82547 if ( empty($code) ) {
82548 $all_messages = array();
82549 foreach ( (array) $this->errors as $code => $messages )
82550 $all_messages = array_merge($all_messages, $messages);
82551
82552 return $all_messages;
82553 }
82554
82555 if ( isset($this->errors[$code]) )
82556 return $this->errors[$code];
82557 else
82558 return array();
82559 }
82560
82561 /**
82562 * Get single error message.
82563 *
82564 * This will get the first message available for the code. If no code is
82565 * given then the first code available will be used.
82566 *
82567 * @since 2.1.0
82568 *
82569 * @param string|int $code Optional. Error code to retrieve message.
82570 * @return string
82571 */
82572 function get_error_message($code = '') {
82573 if ( empty($code) )
82574 $code = $this->get_error_code();
82575 $messages = $this->get_error_messages($code);
82576 if ( empty($messages) )
82577 return '';
82578 return $messages[0];
82579 }
82580
82581 /**
82582 * Retrieve error data for error code.
82583 *
82584 * @since 2.1.0
82585 *
82586 * @param string|int $code Optional. Error code.
82587 * @return mixed Null, if no errors.
82588 */
82589 function get_error_data($code = '') {
82590 if ( empty($code) )
82591 $code = $this->get_error_code();
82592
82593 if ( isset($this->error_data[$code]) )
82594 return $this->error_data[$code];
82595 return null;
82596 }
82597
82598 /**
82599 * Append more error messages to list of error messages.
82600 *
82601 * @since 2.1.0
82602 * @access public
82603 *
82604 * @param string|int $code Error code.
82605 * @param string $message Error message.
82606 * @param mixed $data Optional. Error data.
82607 */
82608 function add($code, $message, $data = '') {
82609 $this->errors[$code][] = $message;
82610 if ( ! empty($data) )
82611 $this->error_data[$code] = $data;
82612 }
82613
82614 /**
82615 * Add data for error code.
82616 *
82617 * The error code can only contain one error data.
82618 *
82619 * @since 2.1.0
82620 *
82621 * @param mixed $data Error data.
82622 * @param string|int $code Error code.
82623 */
82624 function add_data($data, $code = '') {
82625 if ( empty($code) )
82626 $code = $this->get_error_code();
82627
82628 $this->error_data[$code] = $data;
82629 }
82630 }
82631
82632 /**
82633 * Check whether variable is a WordPress Error.
82634 *
82635 * Looks at the object and if a WP_Error class. Does not check to see if the
82636 * parent is also WP_Error, so can't inherit WP_Error and still use this
82637 * function.
82638 *
82639 * @since 2.1.0
82640 *
82641 * @param mixed $thing Check if unknown variable is WordPress Error object.
82642 * @return bool True, if WP_Error. False, if not WP_Error.
82643 */
82644 function is_wp_error($thing) {
82645 if ( is_object($thing) && is_a($thing, 'WP_Error') )
82646 return true;
82647 return false;
82648 }
82649
82650 /**
82651 * A class for displaying various tree-like structures.
82652 *
82653 * Extend the Walker class to use it, see examples at the below. Child classes
82654 * do not need to implement all of the abstract methods in the class. The child
82655 * only needs to implement the methods that are needed. Also, the methods are
82656 * not strictly abstract in that the parameter definition needs to be followed.
82657 * The child classes can have additional parameters.
82658 *
82659 * @package WordPress
82660 * @since 2.1.0
82661 * @abstract
82662 */
82663 class Walker {
82664 /**
82665 * What the class handles.
82666 *
82667 * @since 2.1.0
82668 * @var string
82669 * @access public
82670 */
82671 var $tree_type;
82672
82673 /**
82674 * DB fields to use.
82675 *
82676 * @since 2.1.0
82677 * @var array
82678 * @access protected
82679 */
82680 var $db_fields;
82681
82682 /**
82683 * Max number of pages walked by the paged walker
82684 *
82685 * @since 2.7.0
82686 * @var int
82687 * @access protected
82688 */
82689 var $max_pages = 1;
82690
82691 /**
82692 * Starts the list before the elements are added.
82693 *
82694 * Additional parameters are used in child classes. The args parameter holds
82695 * additional values that may be used with the child class methods. This
82696 * method is called at the start of the output list.
82697 *
82698 * @since 2.1.0
82699 * @abstract
82700 *
82701 * @param string $output Passed by reference. Used to append additional content.
82702 */
82703 # function start_lvl(&$output) {}
82704
82705 /**
82706 * Ends the list of after the elements are added.
82707 *
82708 * Additional parameters are used in child classes. The args parameter holds
82709 * additional values that may be used with the child class methods. This
82710 * method finishes the list at the end of output of the elements.
82711 *
82712 * @since 2.1.0
82713 * @abstract
82714 *
82715 * @param string $output Passed by reference. Used to append additional content.
82716 */
82717 # function end_lvl(&$output) {}
82718
82719 /**
82720 * Start the element output.
82721 *
82722 * Additional parameters are used in child classes. The args parameter holds
82723 * additional values that may be used with the child class methods. Includes
82724 * the element output also.
82725 *
82726 * @since 2.1.0
82727 * @abstract
82728 *
82729 * @param string $output Passed by reference. Used to append additional content.
82730 */
82731 # function start_el(&$output) {}
82732
82733 /**
82734 * Ends the element output, if needed.
82735 *
82736 * Additional parameters are used in child classes. The args parameter holds
82737 * additional values that may be used with the child class methods.
82738 *
82739 * @since 2.1.0
82740 * @abstract
82741 *
82742 * @param string $output Passed by reference. Used to append additional content.
82743 * @param object $thing object involved in walking
82744 * @param int $depth Depth of object
82745 * @param array $args additional arguments
82746 */
82747 function end_el(&$output, $thing, $depth, $args) {}
82748
82749 /**
82750 * Traverse elements to create list from elements.
82751 *
82752 * Display one element if the element doesn't have any children otherwise,
82753 * display the element and its children. Will only traverse up to the max
82754 * depth and no ignore elements under that depth. It is possible to set the
82755 * max depth to include all depths, see walk() method.
82756 *
82757 * This method shouldn't be called directly, use the walk() method instead.
82758 *
82759 * @since 2.5.0
82760 *
82761 * @param object $element Data object
82762 * @param array $children_elements List of elements to continue traversing.
82763 * @param int $max_depth Max depth to traverse.
82764 * @param int $depth Depth of current element.
82765 * @param array $args
82766 * @param string $output Passed by reference. Used to append additional content.
82767 * @return null Null on failure with no changes to parameters.
82768 */
82769 function display_element( $element, &$children_elements, $max_depth, $depth=0, $args, &$output ) {
82770
82771 if ( !$element )
82772 return;
82773
82774 $id_field = $this->db_fields['id'];
82775
82776 //display this element
82777 if ( is_array( $args[0] ) )
82778 $args[0]['has_children'] = ! empty( $children_elements[$element->$id_field] );
82779 $cb_args = array_merge( array(&$output, $element, $depth), $args);
82780 call_user_func_array(array(&$this, 'start_el'), $cb_args);
82781
82782 $id = $element->$id_field;
82783
82784 // descend only when the depth is right and there are childrens for this element
82785 if ( ($max_depth == 0 || $max_depth > $depth+1 ) && isset( $children_elements[$id]) ) {
82786
82787 foreach( $children_elements[ $id ] as $child ){
82788
82789 if ( !isset($newlevel) ) {
82790 $newlevel = true;
82791 //start the child delimiter
82792 $cb_args = array_merge( array(&$output, $depth), $args);
82793 call_user_func_array(array(&$this, 'start_lvl'), $cb_args);
82794 }
82795 $this->display_element( $child, $children_elements, $max_depth, $depth + 1, $args, $output );
82796 }
82797 unset( $children_elements[ $id ] );
82798 }
82799
82800 if ( isset($newlevel) && $newlevel ){
82801 //end the child delimiter
82802 $cb_args = array_merge( array(&$output, $depth), $args);
82803 call_user_func_array(array(&$this, 'end_lvl'), $cb_args);
82804 }
82805
82806 //end this element
82807 $cb_args = array_merge( array(&$output, $element, $depth), $args);
82808 call_user_func_array(array(&$this, 'end_el'), $cb_args);
82809 }
82810
82811 /**
82812 * Display array of elements hierarchically.
82813 *
82814 * It is a generic function which does not assume any existing order of
82815 * elements. max_depth = -1 means flatly display every element. max_depth =
82816 * 0 means display all levels. max_depth > 0 specifies the number of
82817 * display levels.
82818 *
82819 * @since 2.1.0
82820 *
82821 * @param array $elements
82822 * @param int $max_depth
82823 * @return string
82824 */
82825 function walk( $elements, $max_depth) {
82826
82827 $args = array_slice(func_get_args(), 2);
82828 $output = '';
82829
82830 if ($max_depth < -1) //invalid parameter
82831 return $output;
82832
82833 if (empty($elements)) //nothing to walk
82834 return $output;
82835
82836 $id_field = $this->db_fields['id'];
82837 $parent_field = $this->db_fields['parent'];
82838
82839 // flat display
82840 if ( -1 == $max_depth ) {
82841 $empty_array = array();
82842 foreach ( $elements as $e )
82843 $this->display_element( $e, $empty_array, 1, 0, $args, $output );
82844 return $output;
82845 }
82846
82847 /*
82848 * need to display in hierarchical order
82849 * seperate elements into two buckets: top level and children elements
82850 * children_elements is two dimensional array, eg.
82851 * children_elements[10][] contains all sub-elements whose parent is 10.
82852 */
82853 $top_level_elements = array();
82854 $children_elements = array();
82855 foreach ( $elements as $e) {
82856 if ( 0 == $e->$parent_field )
82857 $top_level_elements[] = $e;
82858 else
82859 $children_elements[ $e->$parent_field ][] = $e;
82860 }
82861
82862 /*
82863 * when none of the elements is top level
82864 * assume the first one must be root of the sub elements
82865 */
82866 if ( empty($top_level_elements) ) {
82867
82868 $first = array_slice( $elements, 0, 1 );
82869 $root = $first[0];
82870
82871 $top_level_elements = array();
82872 $children_elements = array();
82873 foreach ( $elements as $e) {
82874 if ( $root->$parent_field == $e->$parent_field )
82875 $top_level_elements[] = $e;
82876 else
82877 $children_elements[ $e->$parent_field ][] = $e;
82878 }
82879 }
82880
82881 foreach ( $top_level_elements as $e )
82882 $this->display_element( $e, $children_elements, $max_depth, 0, $args, $output );
82883
82884 /*
82885 * if we are displaying all levels, and remaining children_elements is not empty,
82886 * then we got orphans, which should be displayed regardless
82887 */
82888 if ( ( $max_depth == 0 ) && count( $children_elements ) > 0 ) {
82889 $empty_array = array();
82890 foreach ( $children_elements as $orphans )
82891 foreach( $orphans as $op )
82892 $this->display_element( $op, $empty_array, 1, 0, $args, $output );
82893 }
82894
82895 return $output;
82896 }
82897
82898 /**
82899 * paged_walk() - produce a page of nested elements
82900 *
82901 * Given an array of hierarchical elements, the maximum depth, a specific page number,
82902 * and number of elements per page, this function first determines all top level root elements
82903 * belonging to that page, then lists them and all of their children in hierarchical order.
82904 *
82905 * @package WordPress
82906 * @since 2.7
82907 * @param $max_depth = 0 means display all levels; $max_depth > 0 specifies the number of display levels.
82908 * @param $page_num the specific page number, beginning with 1.
82909 * @return XHTML of the specified page of elements
82910 */
82911 function paged_walk( $elements, $max_depth, $page_num, $per_page ) {
82912
82913 /* sanity check */
82914 if ( empty($elements) || $max_depth < -1 )
82915 return '';
82916
82917 $args = array_slice( func_get_args(), 4 );
82918 $output = '';
82919
82920 $id_field = $this->db_fields['id'];
82921 $parent_field = $this->db_fields['parent'];
82922
82923 $count = -1;
82924 if ( -1 == $max_depth )
82925 $total_top = count( $elements );
82926 if ( $page_num < 1 || $per_page < 0 ) {
82927 // No paging
82928 $paging = false;
82929 $start = 0;
82930 if ( -1 == $max_depth )
82931 $end = $total_top;
82932 $this->max_pages = 1;
82933 } else {
82934 $paging = true;
82935 $start = ( (int)$page_num - 1 ) * (int)$per_page;
82936 $end = $start + $per_page;
82937 if ( -1 == $max_depth )
82938 $this->max_pages = ceil($total_top / $per_page);
82939 }
82940
82941 // flat display
82942 if ( -1 == $max_depth ) {
82943 if ( !empty($args[0]['reverse_top_level']) ) {
82944 $elements = array_reverse( $elements );
82945 $oldstart = $start;
82946 $start = $total_top - $end;
82947 $end = $total_top - $oldstart;
82948 }
82949
82950 $empty_array = array();
82951 foreach ( $elements as $e ) {
82952 $count++;
82953 if ( $count < $start )
82954 continue;
82955 if ( $count >= $end )
82956 break;
82957 $this->display_element( $e, $empty_array, 1, 0, $args, $output );
82958 }
82959 return $output;
82960 }
82961
82962 /*
82963 * seperate elements into two buckets: top level and children elements
82964 * children_elements is two dimensional array, eg.
82965 * children_elements[10][] contains all sub-elements whose parent is 10.
82966 */
82967 $top_level_elements = array();
82968 $children_elements = array();
82969 foreach ( $elements as $e) {
82970 if ( 0 == $e->$parent_field )
82971 $top_level_elements[] = $e;
82972 else
82973 $children_elements[ $e->$parent_field ][] = $e;
82974 }
82975
82976 $total_top = count( $top_level_elements );
82977 if ( $paging )
82978 $this->max_pages = ceil($total_top / $per_page);
82979 else
82980 $end = $total_top;
82981
82982 if ( !empty($args[0]['reverse_top_level']) ) {
82983 $top_level_elements = array_reverse( $top_level_elements );
82984 $oldstart = $start;
82985 $start = $total_top - $end;
82986 $end = $total_top - $oldstart;
82987 }
82988 if ( !empty($args[0]['reverse_children']) ) {
82989 foreach ( $children_elements as $parent => $children )
82990 $children_elements[$parent] = array_reverse( $children );
82991 }
82992
82993 foreach ( $top_level_elements as $e ) {
82994 $count++;
82995
82996 //for the last page, need to unset earlier children in order to keep track of orphans
82997 if ( $end >= $total_top && $count < $start )
82998 $this->unset_children( $e, $children_elements );
82999
83000 if ( $count < $start )
83001 continue;
83002
83003 if ( $count >= $end )
83004 break;
83005
83006 $this->display_element( $e, $children_elements, $max_depth, 0, $args, $output );
83007 }
83008
83009 if ( $end >= $total_top && count( $children_elements ) > 0 ) {
83010 $empty_array = array();
83011 foreach ( $children_elements as $orphans )
83012 foreach( $orphans as $op )
83013 $this->display_element( $op, $empty_array, 1, 0, $args, $output );
83014 }
83015
83016 return $output;
83017 }
83018
83019 function get_number_of_root_elements( $elements ){
83020
83021 $num = 0;
83022 $parent_field = $this->db_fields['parent'];
83023
83024 foreach ( $elements as $e) {
83025 if ( 0 == $e->$parent_field )
83026 $num++;
83027 }
83028 return $num;
83029 }
83030
83031 // unset all the children for a given top level element
83032 function unset_children( $e, &$children_elements ){
83033
83034 if ( !$e || !$children_elements )
83035 return;
83036
83037 $id_field = $this->db_fields['id'];
83038 $id = $e->$id_field;
83039
83040 if ( !empty($children_elements[$id]) && is_array($children_elements[$id]) )
83041 foreach ( (array) $children_elements[$id] as $child )
83042 $this->unset_children( $child, $children_elements );
83043
83044 if ( isset($children_elements[$id]) )
83045 unset( $children_elements[$id] );
83046
83047 }
83048 }
83049
83050 /**
83051 * Create HTML list of pages.
83052 *
83053 * @package WordPress
83054 * @since 2.1.0
83055 * @uses Walker
83056 */
83057 class Walker_Page extends Walker {
83058 /**
83059 * @see Walker::$tree_type
83060 * @since 2.1.0
83061 * @var string
83062 */
83063 var $tree_type = 'page';
83064
83065 /**
83066 * @see Walker::$db_fields
83067 * @since 2.1.0
83068 * @todo Decouple this.
83069 * @var array
83070 */
83071 var $db_fields = array ('parent' => 'post_parent', 'id' => 'ID');
83072
83073 /**
83074 * @see Walker::start_lvl()
83075 * @since 2.1.0
83076 *
83077 * @param string $output Passed by reference. Used to append additional content.
83078 * @param int $depth Depth of page. Used for padding.
83079 */
83080 function start_lvl(&$output, $depth) {
83081 $indent = str_repeat("\t", $depth);
83082 $output .= "\n$indent<ul>\n";
83083 }
83084
83085 /**
83086 * @see Walker::end_lvl()
83087 * @since 2.1.0
83088 *
83089 * @param string $output Passed by reference. Used to append additional content.
83090 * @param int $depth Depth of page. Used for padding.
83091 */
83092 function end_lvl(&$output, $depth) {
83093 $indent = str_repeat("\t", $depth);
83094 $output .= "$indent</ul>\n";
83095 }
83096
83097 /**
83098 * @see Walker::start_el()
83099 * @since 2.1.0
83100 *
83101 * @param string $output Passed by reference. Used to append additional content.
83102 * @param object $page Page data object.
83103 * @param int $depth Depth of page. Used for padding.
83104 * @param int $current_page Page ID.
83105 * @param array $args
83106 */
83107 function start_el(&$output, $page, $depth, $args, $current_page) {
83108 if ( $depth )
83109 $indent = str_repeat("\t", $depth);
83110 else
83111 $indent = '';
83112
83113 extract($args, EXTR_SKIP);
83114 $css_class = 'page_item page-item-'.$page->ID;
83115 if ( !empty($current_page) ) {
83116 $_current_page = get_page( $current_page );
83117 if ( isset($_current_page->ancestors) && in_array($page->ID, (array) $_current_page->ancestors) )
83118 $css_class .= ' current_page_ancestor';
83119 if ( $page->ID == $current_page )
83120 $css_class .= ' current_page_item';
83121 elseif ( $_current_page && $page->ID == $_current_page->post_parent )
83122 $css_class .= ' current_page_parent';
83123 } elseif ( $page->ID == get_option('page_for_posts') ) {
83124 $css_class .= ' current_page_parent';
83125 }
83126
83127 $output .= $indent . '<li class="' . $css_class . '"><a href="' . get_page_link($page->ID) . '" title="' . attribute_escape(apply_filters('the_title', $page->post_title)) . '">' . $link_before . apply_filters('the_title', $page->post_title) . $link_after . '</a>';
83128
83129 if ( !empty($show_date) ) {
83130 if ( 'modified' == $show_date )
83131 $time = $page->post_modified;
83132 else
83133 $time = $page->post_date;
83134
83135 $output .= " " . mysql2date($date_format, $time);
83136 }
83137 }
83138
83139 /**
83140 * @see Walker::end_el()
83141 * @since 2.1.0
83142 *
83143 * @param string $output Passed by reference. Used to append additional content.
83144 * @param object $page Page data object. Not used.
83145 * @param int $depth Depth of page. Not Used.
83146 */
83147 function end_el(&$output, $page, $depth, $args) {
83148 $output .= "</li>\n";
83149 }
83150
83151 }
83152
83153 /**
83154 * Create HTML dropdown list of pages.
83155 *
83156 * @package WordPress
83157 * @since 2.1.0
83158 * @uses Walker
83159 */
83160 class Walker_PageDropdown extends Walker {
83161 /**
83162 * @see Walker::$tree_type
83163 * @since 2.1.0
83164 * @var string
83165 */
83166 var $tree_type = 'page';
83167
83168 /**
83169 * @see Walker::$db_fields
83170 * @since 2.1.0
83171 * @todo Decouple this
83172 * @var array
83173 */
83174 var $db_fields = array ('parent' => 'post_parent', 'id' => 'ID');
83175
83176 /**
83177 * @see Walker::start_el()
83178 * @since 2.1.0
83179 *
83180 * @param string $output Passed by reference. Used to append additional content.
83181 * @param object $page Page data object.
83182 * @param int $depth Depth of page in reference to parent pages. Used for padding.
83183 * @param array $args Uses 'selected' argument for selected page to set selected HTML attribute for option element.
83184 */
83185 function start_el(&$output, $page, $depth, $args) {
83186 $pad = str_repeat(' ', $depth * 3);
83187
83188 $output .= "\t<option class=\"level-$depth\" value=\"$page->ID\"";
83189 if ( $page->ID == $args['selected'] )
83190 $output .= ' selected="selected"';
83191 $output .= '>';
83192 $title = wp_specialchars($page->post_title);
83193 $output .= "$pad$title";
83194 $output .= "</option>\n";
83195 }
83196 }
83197
83198 /**
83199 * Create HTML list of categories.
83200 *
83201 * @package WordPress
83202 * @since 2.1.0
83203 * @uses Walker
83204 */
83205 class Walker_Category extends Walker {
83206 /**
83207 * @see Walker::$tree_type
83208 * @since 2.1.0
83209 * @var string
83210 */
83211 var $tree_type = 'category';
83212
83213 /**
83214 * @see Walker::$db_fields
83215 * @since 2.1.0
83216 * @todo Decouple this
83217 * @var array
83218 */
83219 var $db_fields = array ('parent' => 'parent', 'id' => 'term_id');
83220
83221 /**
83222 * @see Walker::start_lvl()
83223 * @since 2.1.0
83224 *
83225 * @param string $output Passed by reference. Used to append additional content.
83226 * @param int $depth Depth of category. Used for tab indentation.
83227 * @param array $args Will only append content if style argument value is 'list'.
83228 */
83229 function start_lvl(&$output, $depth, $args) {
83230 if ( 'list' != $args['style'] )
83231 return;
83232
83233 $indent = str_repeat("\t", $depth);
83234 $output .= "$indent<ul class='children'>\n";
83235 }
83236
83237 /**
83238 * @see Walker::end_lvl()
83239 * @since 2.1.0
83240 *
83241 * @param string $output Passed by reference. Used to append additional content.
83242 * @param int $depth Depth of category. Used for tab indentation.
83243 * @param array $args Will only append content if style argument value is 'list'.
83244 */
83245 function end_lvl(&$output, $depth, $args) {
83246 if ( 'list' != $args['style'] )
83247 return;
83248
83249 $indent = str_repeat("\t", $depth);
83250 $output .= "$indent</ul>\n";
83251 }
83252
83253 /**
83254 * @see Walker::start_el()
83255 * @since 2.1.0
83256 *
83257 * @param string $output Passed by reference. Used to append additional content.
83258 * @param object $category Category data object.
83259 * @param int $depth Depth of category in reference to parents.
83260 * @param array $args
83261 */
83262 function start_el(&$output, $category, $depth, $args) {
83263 extract($args);
83264
83265 $cat_name = attribute_escape( $category->name);
83266 $cat_name = apply_filters( 'list_cats', $cat_name, $category );
83267 $link = '<a href="' . get_category_link( $category->term_id ) . '" ';
83268 if ( $use_desc_for_title == 0 || empty($category->description) )
83269 $link .= 'title="' . sprintf(__( 'View all posts filed under %s' ), $cat_name) . '"';
83270 else
83271 $link .= 'title="' . attribute_escape( apply_filters( 'category_description', $category->description, $category )) . '"';
83272 $link .= '>';
83273 $link .= $cat_name . '</a>';
83274
83275 if ( (! empty($feed_image)) || (! empty($feed)) ) {
83276 $link .= ' ';
83277
83278 if ( empty($feed_image) )
83279 $link .= '(';
83280
83281 $link .= '<a href="' . get_category_feed_link($category->term_id, $feed_type) . '"';
83282
83283 if ( empty($feed) )
83284 $alt = ' alt="' . sprintf(__( 'Feed for all posts filed under %s' ), $cat_name ) . '"';
83285 else {
83286 $title = ' title="' . $feed . '"';
83287 $alt = ' alt="' . $feed . '"';
83288 $name = $feed;
83289 $link .= $title;
83290 }
83291
83292 $link .= '>';
83293
83294 if ( empty($feed_image) )
83295 $link .= $name;
83296 else
83297 $link .= "<img src='$feed_image'$alt$title" . ' />';
83298 $link .= '</a>';
83299 if ( empty($feed_image) )
83300 $link .= ')';
83301 }
83302
83303 if ( isset($show_count) && $show_count )
83304 $link .= ' (' . intval($category->count) . ')';
83305
83306 if ( isset($show_date) && $show_date ) {
83307 $link .= ' ' . gmdate('Y-m-d', $category->last_update_timestamp);
83308 }
83309
83310 if ( isset($current_category) && $current_category )
83311 $_current_category = get_category( $current_category );
83312
83313 if ( 'list' == $args['style'] ) {
83314 $output .= "\t<li";
83315 $class = 'cat-item cat-item-'.$category->term_id;
83316 if ( isset($current_category) && $current_category && ($category->term_id == $current_category) )
83317 $class .= ' current-cat';
83318 elseif ( isset($_current_category) && $_current_category && ($category->term_id == $_current_category->parent) )
83319 $class .= ' current-cat-parent';
83320 $output .= ' class="'.$class.'"';
83321 $output .= ">$link\n";
83322 } else {
83323 $output .= "\t$link<br />\n";
83324 }
83325 }
83326
83327 /**
83328 * @see Walker::end_el()
83329 * @since 2.1.0
83330 *
83331 * @param string $output Passed by reference. Used to append additional content.
83332 * @param object $page Not used.
83333 * @param int $depth Depth of category. Not used.
83334 * @param array $args Only uses 'list' for whether should append to output.
83335 */
83336 function end_el(&$output, $page, $depth, $args) {
83337 if ( 'list' != $args['style'] )
83338 return;
83339
83340 $output .= "</li>\n";
83341 }
83342
83343 }
83344
83345 /**
83346 * Create HTML dropdown list of Categories.
83347 *
83348 * @package WordPress
83349 * @since 2.1.0
83350 * @uses Walker
83351 */
83352 class Walker_CategoryDropdown extends Walker {
83353 /**
83354 * @see Walker::$tree_type
83355 * @since 2.1.0
83356 * @var string
83357 */
83358 var $tree_type = 'category';
83359
83360 /**
83361 * @see Walker::$db_fields
83362 * @since 2.1.0
83363 * @todo Decouple this
83364 * @var array
83365 */
83366 var $db_fields = array ('parent' => 'parent', 'id' => 'term_id');
83367
83368 /**
83369 * @see Walker::start_el()
83370 * @since 2.1.0
83371 *
83372 * @param string $output Passed by reference. Used to append additional content.
83373 * @param object $category Category data object.
83374 * @param int $depth Depth of category. Used for padding.
83375 * @param array $args Uses 'selected', 'show_count', and 'show_last_update' keys, if they exist.
83376 */
83377 function start_el(&$output, $category, $depth, $args) {
83378 $pad = str_repeat(' ', $depth * 3);
83379
83380 $cat_name = apply_filters('list_cats', $category->name, $category);
83381 $output .= "\t<option class=\"level-$depth\" value=\"".$category->term_id."\"";
83382 if ( $category->term_id == $args['selected'] )
83383 $output .= ' selected="selected"';
83384 $output .= '>';
83385 $output .= $pad.$cat_name;
83386 if ( $args['show_count'] )
83387 $output .= '  ('. $category->count .')';
83388 if ( $args['show_last_update'] ) {
83389 $format = 'Y-m-d';
83390 $output .= '  ' . gmdate($format, $category->last_update_timestamp);
83391 }
83392 $output .= "</option>\n";
83393 }
83394 }
83395
83396 /**
83397 * Send XML response back to AJAX request.
83398 *
83399 * @package WordPress
83400 * @since 2.1.0
83401 */
83402 class WP_Ajax_Response {
83403 /**
83404 * Store XML responses to send.
83405 *
83406 * @since 2.1.0
83407 * @var array
83408 * @access private
83409 */
83410 var $responses = array();
83411
83412 /**
83413 * PHP4 Constructor - Passes args to {@link WP_Ajax_Response::add()}.
83414 *
83415 * @since 2.1.0
83416 * @see WP_Ajax_Response::add()
83417 *
83418 * @param string|array $args Optional. Will be passed to add() method.
83419 * @return WP_Ajax_Response
83420 */
83421 function WP_Ajax_Response( $args = '' ) {
83422 if ( !empty($args) )
83423 $this->add($args);
83424 }
83425
83426 /**
83427 * Append to XML response based on given arguments.
83428 *
83429 * The arguments that can be passed in the $args parameter are below. It is
83430 * also possible to pass a WP_Error object in either the 'id' or 'data'
83431 * argument. The parameter isn't actually optional, content should be given
83432 * in order to send the correct response.
83433 *
83434 * 'what' argument is a string that is the XMLRPC response type.
83435 * 'action' argument is a boolean or string that acts like a nonce.
83436 * 'id' argument can be WP_Error or an integer.
83437 * 'old_id' argument is false by default or an integer of the previous ID.
83438 * 'position' argument is an integer or a string with -1 = top, 1 = bottom,
83439 * html ID = after, -html ID = before.
83440 * 'data' argument is a string with the content or message.
83441 * 'supplemental' argument is an array of strings that will be children of
83442 * the supplemental element.
83443 *
83444 * @since 2.1.0
83445 *
83446 * @param string|array $args Override defaults.
83447 * @return string XML response.
83448 */
83449 function add( $args = '' ) {
83450 $defaults = array(
83451 'what' => 'object', 'action' => false,
83452 'id' => '0', 'old_id' => false,
83453 'position' => 1,
83454 'data' => '', 'supplemental' => array()
83455 );
83456
83457 $r = wp_parse_args( $args, $defaults );
83458 extract( $r, EXTR_SKIP );
83459 $position = preg_replace( '/[^a-z0-9:_-]/i', '', $position );
83460
83461 if ( is_wp_error($id) ) {
83462 $data = $id;
83463 $id = 0;
83464 }
83465
83466 $response = '';
83467 if ( is_wp_error($data) ) {
83468 foreach ( (array) $data->get_error_codes() as $code ) {
83469 $response .= "<wp_error code='$code'><![CDATA[" . $data->get_error_message($code) . "]]></wp_error>";
83470 if ( !$error_data = $data->get_error_data($code) )
83471 continue;
83472 $class = '';
83473 if ( is_object($error_data) ) {
83474 $class = ' class="' . get_class($error_data) . '"';
83475 $error_data = get_object_vars($error_data);
83476 }
83477
83478 $response .= "<wp_error_data code='$code'$class>";
83479
83480 if ( is_scalar($error_data) ) {
83481 $response .= "<![CDATA[$error_data]]>";
83482 } elseif ( is_array($error_data) ) {
83483 foreach ( $error_data as $k => $v )
83484 $response .= "<$k><![CDATA[$v]]></$k>";
83485 }
83486
83487 $response .= "</wp_error_data>";
83488 }
83489 } else {
83490 $response = "<response_data><![CDATA[$data]]></response_data>";
83491 }
83492
83493 $s = '';
83494 if ( is_array($supplemental) ) {
83495 foreach ( $supplemental as $k => $v )
83496 $s .= "<$k><![CDATA[$v]]></$k>";
83497 $s = "<supplemental>$s</supplemental>";
83498 }
83499
83500 if ( false === $action )
83501 $action = $_POST['action'];
83502
83503 $x = '';
83504 $x .= "<response action='{$action}_$id'>"; // The action attribute in the xml output is formatted like a nonce action
83505 $x .= "<$what id='$id' " . ( false === $old_id ? '' : "old_id='$old_id' " ) . "position='$position'>";
83506 $x .= $response;
83507 $x .= $s;
83508 $x .= "</$what>";
83509 $x .= "</response>";
83510
83511 $this->responses[] = $x;
83512 return $x;
83513 }
83514
83515 /**
83516 * Display XML formatted responses.
83517 *
83518 * Sets the content type header to text/xml.
83519 *
83520 * @since 2.1.0
83521 */
83522 function send() {
83523 header('Content-Type: text/xml');
83524 echo "<?xml version='1.0' standalone='yes'?><wp_ajax>";
83525 foreach ( (array) $this->responses as $response )
83526 echo $response;
83527 echo '</wp_ajax>';
83528 die();
83529 }
83530 }
83531
83532 ?>