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