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