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