Wordpress 2.7.1
[autoinstalls/wordpress.git] / wp-includes / post-template.php
1 <?php
2 /**
3  * WordPress Post Template Functions.
4  *
5  * Gets content for the current post in the loop.
6  *
7  * @package WordPress
8  * @subpackage Template
9  */
10
11 /**
12  * Display the ID of the current item in the WordPress Loop.
13  *
14  * @since 0.71
15  * @uses $id
16  */
17 function the_ID() {
18         global $id;
19         echo $id;
20 }
21
22 /**
23  * Retrieve the ID of the current item in the WordPress Loop.
24  *
25  * @since 2.1.0
26  * @uses $id
27  *
28  * @return unknown
29  */
30 function get_the_ID() {
31         global $id;
32         return $id;
33 }
34
35 /**
36  * Display or retrieve the current post title with optional content.
37  *
38  * @since 0.71
39  *
40  * @param string $before Optional. Content to prepend to the title.
41  * @param string $after Optional. Content to append to the title.
42  * @param bool $echo Optional, default to true.Whether to display or return.
43  * @return null|string Null on no title. String if $echo parameter is false.
44  */
45 function the_title($before = '', $after = '', $echo = true) {
46         $title = get_the_title();
47
48         if ( strlen($title) == 0 )
49                 return;
50
51         $title = $before . $title . $after;
52
53         if ( $echo )
54                 echo $title;
55         else
56                 return $title;
57 }
58
59 /**
60  * Sanitize the current title when retrieving or displaying.
61  *
62  * Works like {@link the_title()}, except the parameters can be in a string or
63  * an array. See the function for what can be override in the $args parameter.
64  *
65  * The title before it is displayed will have the tags stripped and {@link
66  * attribute_escape()} before it is passed to the user or displayed. The default
67  * as with {@link the_title()}, is to display the title.
68  *
69  * @since 2.3.0
70  *
71  * @param string|array $args Optional. Override the defaults.
72  * @return string|null Null on failure or display. String when echo is false.
73  */
74 function the_title_attribute( $args = '' ) {
75         $title = get_the_title();
76
77         if ( strlen($title) == 0 )
78                 return;
79
80         $defaults = array('before' => '', 'after' =>  '', 'echo' => true);
81         $r = wp_parse_args($args, $defaults);
82         extract( $r, EXTR_SKIP );
83
84
85         $title = $before . $title . $after;
86         $title = attribute_escape(strip_tags($title));
87
88         if ( $echo )
89                 echo $title;
90         else
91                 return $title;
92 }
93
94 /**
95  * Retrieve post title.
96  *
97  * If the post is protected and the visitor is not an admin, then "Protected"
98  * will be displayed before the post title. If the post is private, then
99  * "Private" will be located before the post title.
100  *
101  * @since 0.71
102  *
103  * @param int $id Optional. Post ID.
104  * @return string
105  */
106 function get_the_title( $id = 0 ) {
107         $post = &get_post($id);
108
109         $title = $post->post_title;
110
111         if ( !is_admin() ) {
112                 if ( !empty($post->post_password) )
113                         $title = sprintf(__('Protected: %s'), $title);
114                 else if ( isset($post->post_status) && 'private' == $post->post_status )
115                         $title = sprintf(__('Private: %s'), $title);
116         }
117         return apply_filters( 'the_title', $title );
118 }
119
120 /**
121  * Display the Post Global Unique Identifier (guid).
122  *
123  * The guid will appear to be a link, but should not be used as an link to the
124  * post. The reason you should not use it as a link, is because of moving the
125  * blog across domains.
126  *
127  * @since 1.5.0
128  *
129  * @param int $id Optional. Post ID.
130  */
131 function the_guid( $id = 0 ) {
132         echo get_the_guid($id);
133 }
134
135 /**
136  * Retrieve the Post Global Unique Identifier (guid).
137  *
138  * The guid will appear to be a link, but should not be used as an link to the
139  * post. The reason you should not use it as a link, is because of moving the
140  * blog across domains.
141  *
142  * @since 1.5.0
143  *
144  * @param int $id Optional. Post ID.
145  * @return string
146  */
147 function get_the_guid( $id = 0 ) {
148         $post = &get_post($id);
149
150         return apply_filters('get_the_guid', $post->guid);
151 }
152
153 /**
154  * Display the post content.
155  *
156  * @since 0.71
157  *
158  * @param string $more_link_text Optional. Content for when there is more text.
159  * @param string $stripteaser Optional. Teaser content before the more text.
160  * @param string $more_file Optional. Not used.
161  */
162 function the_content($more_link_text = null, $stripteaser = 0, $more_file = '') {
163         $content = get_the_content($more_link_text, $stripteaser, $more_file);
164         $content = apply_filters('the_content', $content);
165         $content = str_replace(']]>', ']]&gt;', $content);
166         echo $content;
167 }
168
169 /**
170  * Retrieve the post content.
171  *
172  * @since 0.71
173  *
174  * @param string $more_link_text Optional. Content for when there is more text.
175  * @param string $stripteaser Optional. Teaser content before the more text.
176  * @param string $more_file Optional. Not used.
177  * @return string
178  */
179 function get_the_content($more_link_text = null, $stripteaser = 0, $more_file = '') {
180         global $id, $post, $more, $page, $pages, $multipage, $preview, $pagenow;
181
182         if ( null === $more_link_text )
183                 $more_link_text = __( '(more...)' );
184
185         $output = '';
186
187         // If post password required and it doesn't match the cookie.
188         if ( post_password_required($post) ) {
189                 $output = get_the_password_form();
190                 return $output;
191         }
192
193         if ( $more_file != '' )
194                 $file = $more_file;
195         else
196                 $file = $pagenow; //$_SERVER['PHP_SELF'];
197
198         if ( $page > count($pages) ) // if the requested page doesn't exist
199                 $page = count($pages); // give them the highest numbered page that DOES exist
200
201         $content = $pages[$page-1];
202         if ( preg_match('/<!--more(.*?)?-->/', $content, $matches) ) {
203                 $content = explode($matches[0], $content, 2);
204                 if ( !empty($matches[1]) && !empty($more_link_text) )
205                         $more_link_text = strip_tags(wp_kses_no_null(trim($matches[1])));
206         } else {
207                 $content = array($content);
208         }
209         if ( (false !== strpos($post->post_content, '<!--noteaser-->') && ((!$multipage) || ($page==1))) )
210                 $stripteaser = 1;
211         $teaser = $content[0];
212         if ( ($more) && ($stripteaser) )
213                 $teaser = '';
214         $output .= $teaser;
215         if ( count($content) > 1 ) {
216                 if ( $more ) {
217                         $output .= '<span id="more-'.$id.'"></span>'.$content[1];
218                 } else {
219                         $output = balanceTags($output);
220                         if ( ! empty($more_link_text) )
221                                 $output .= ' <a href="'. get_permalink() . "#more-$id\" class=\"more-link\">$more_link_text</a>";
222                 }
223
224         }
225         if ( $preview ) // preview fix for javascript bug with foreign languages
226                 $output =       preg_replace_callback('/\%u([0-9A-F]{4})/', create_function('$match', 'return "&#" . base_convert($match[1], 16, 10) . ";";'), $output);
227
228         return $output;
229 }
230
231 /**
232  * Display the post excerpt.
233  *
234  * @since 0.71
235  * @uses apply_filters() Calls 'the_excerpt' hook on post excerpt.
236  */
237 function the_excerpt() {
238         echo apply_filters('the_excerpt', get_the_excerpt());
239 }
240
241 /**
242  * Retrieve the post excerpt.
243  *
244  * @since 0.71
245  *
246  * @param mixed $deprecated Not used.
247  * @return string
248  */
249 function get_the_excerpt($deprecated = '') {
250         global $post;
251         $output = '';
252         $output = $post->post_excerpt;
253         if ( post_password_required($post) ) {
254                 $output = __('There is no excerpt because this is a protected post.');
255                 return $output;
256         }
257
258         return apply_filters('get_the_excerpt', $output);
259 }
260
261 /**
262  * Whether post has excerpt.
263  *
264  * @since 2.3.0
265  *
266  * @param int $id Optional. Post ID.
267  * @return bool
268  */
269 function has_excerpt( $id = 0 ) {
270         $post = &get_post( $id );
271         return ( !empty( $post->post_excerpt ) );
272 }
273
274 /**
275  * Display the classes for the post div.
276  *
277  * @since 2.7.0
278  *
279  * @param string|array $class One or more classes to add to the class list.
280  * @param int $post_id An optional post ID.
281  */
282 function post_class( $class = '', $post_id = null ) {
283         // Separates classes with a single space, collates classes for post DIV
284         echo 'class="' . join( ' ', get_post_class( $class, $post_id ) ) . '"';
285 }
286
287 /**
288  * Retrieve the classes for the post div as an array.
289  *
290  * The class names are add are many. If the post is a sticky, then the 'sticky'
291  * class name. The class 'hentry' is always added to each post. For each
292  * category, the class will be added with 'category-' with category slug is
293  * added. The tags are the same way as the categories with 'tag-' before the tag
294  * slug. All classes are passed through the filter, 'post_class' with the list
295  * of classes, followed by $class parameter value, with the post ID as the last
296  * parameter.
297  *
298  * @since 2.7.0
299  *
300  * @param string|array $class One or more classes to add to the class list.
301  * @param int $post_id An optional post ID.
302  * @return array Array of classes.
303  */
304 function get_post_class( $class = '', $post_id = null ) {
305         $post = get_post($post_id);
306
307         $classes = array();
308
309         $classes[] = $post->post_type;
310
311         // sticky for Sticky Posts
312         if ( is_sticky($post->ID) && is_home())
313                 $classes[] = 'sticky';
314
315         // hentry for hAtom compliace
316         $classes[] = 'hentry';
317
318         // Categories
319         foreach ( (array) get_the_category($post->ID) as $cat ) {
320                 if ( empty($cat->slug ) )
321                         continue;
322                 $classes[] = 'category-' . $cat->slug;
323         }
324
325         // Tags
326         foreach ( (array) get_the_tags($post->ID) as $tag ) {
327                 if ( empty($tag->slug ) )
328                         continue;
329                 $classes[] = 'tag-' . $tag->slug;
330         }
331
332         if ( !empty($class) ) {
333                 if ( !is_array( $class ) )
334                         $class = preg_split('#\s+#', $class);
335                 $classes = array_merge($classes, $class);
336         }
337
338         return apply_filters('post_class', $classes, $class, $post_id);
339 }
340
341 /**
342  * Whether post requires password and correct password has been provided.
343  *
344  * @since 2.7.0
345  *
346  * @param int|object $post An optional post.  Global $post used if not provided.
347  * @return bool false if a password is not required or the correct password cookie is present, true otherwise.
348  */
349 function post_password_required( $post = null ) {
350         $post = get_post($post);
351
352         if ( empty($post->post_password) )
353                 return false;
354
355         if ( !isset($_COOKIE['wp-postpass_' . COOKIEHASH]) )
356                 return true;
357
358         if ( $_COOKIE['wp-postpass_' . COOKIEHASH] != $post->post_password )
359                 return true;
360
361         return false;
362 }
363
364 /**
365  * Display "sticky" CSS class, if a post is sticky.
366  *
367  * @since 2.7.0
368  *
369  * @param int $post_id An optional post ID.
370  */
371 function sticky_class( $post_id = null ) {
372         if ( !is_sticky($post_id) )
373                 return;
374
375         echo " sticky";
376 }
377
378 /**
379  * Page Template Functions for usage in Themes
380  *
381  * @package WordPress
382  * @subpackage Template
383  */
384
385 /**
386  * The formatted output of a list of pages.
387  *
388  * Displays page links for paginated posts (i.e. includes the <!--nextpage-->.
389  * Quicktag one or more times). This tag must be within The Loop.
390  *
391  * The defaults for overwriting are:
392  * 'next_or_number' - Default is 'number' (string). Indicates whether page
393  *      numbers should be used. Valid values are number and next.
394  * 'nextpagelink' - Default is 'Next Page' (string). Text for link to next page.
395  *      of the bookmark.
396  * 'previouspagelink' - Default is 'Previous Page' (string). Text for link to
397  *      previous page, if available.
398  * 'pagelink' - Default is '%' (String).Format string for page numbers. The % in
399  *      the parameter string will be replaced with the page number, so Page %
400  *      generates "Page 1", "Page 2", etc. Defaults to %, just the page number.
401  * 'before' - Default is '<p> Pages:' (string). The html or text to prepend to
402  *      each bookmarks.
403  * 'after' - Default is '</p>' (string). The html or text to append to each
404  *      bookmarks.
405  * 'more_file' - Default is '' (string) Page the links should point to. Defaults
406  *      to the current page.
407  * 'link_before' - Default is '' (string). The html or text to prepend to each
408  *      Pages link inside the <a> tag.
409  * 'link_after' - Default is '' (string). The html or text to append to each
410  *      Pages link inside the <a> tag.
411  *
412  * @since 1.2.0
413  * @access private
414  *
415  * @param string|array $args Optional. Overwrite the defaults.
416  * @return string Formatted output in HTML.
417  */
418 function wp_link_pages($args = '') {
419         $defaults = array(
420                 'before' => '<p>' . __('Pages:'), 'after' => '</p>',
421                 'link_before' => '', 'link_after' => '',
422                 'next_or_number' => 'number', 'nextpagelink' => __('Next page'),
423                 'previouspagelink' => __('Previous page'), 'pagelink' => '%',
424                 'more_file' => '', 'echo' => 1
425         );
426
427         $r = wp_parse_args( $args, $defaults );
428         extract( $r, EXTR_SKIP );
429
430         global $post, $page, $numpages, $multipage, $more, $pagenow;
431         if ( $more_file != '' )
432                 $file = $more_file;
433         else
434                 $file = $pagenow;
435
436         $output = '';
437         if ( $multipage ) {
438                 if ( 'number' == $next_or_number ) {
439                         $output .= $before;
440                         for ( $i = 1; $i < ($numpages+1); $i = $i + 1 ) {
441                                 $j = str_replace('%',"$i",$pagelink);
442                                 $output .= ' ';
443                                 if ( ($i != $page) || ((!$more) && ($page==1)) ) {
444                                         if ( 1 == $i ) {
445                                                 $output .= '<a href="' . get_permalink() . '">';
446                                         } else {
447                                                 if ( '' == get_option('permalink_structure') || in_array($post->post_status, array('draft', 'pending')) )
448                                                         $output .= '<a href="' . get_permalink() . '&amp;page=' . $i . '">';
449                                                 else
450                                                         $output .= '<a href="' . trailingslashit(get_permalink()) . user_trailingslashit($i, 'single_paged') . '">';
451                                         }
452
453                                 }
454                                 $output .= $link_before;
455                                 $output .= $j;
456                                 $output .= $link_after;
457                                 if ( ($i != $page) || ((!$more) && ($page==1)) )
458                                         $output .= '</a>';
459                         }
460                         $output .= $after;
461                 } else {
462                         if ( $more ) {
463                                 $output .= $before;
464                                 $i = $page - 1;
465                                 if ( $i && $more ) {
466                                         if ( 1 == $i ) {
467                                                 $output .= '<a href="' . get_permalink() . '">' . $link_before. $previouspagelink . $link_after . '</a>';
468                                         } else {
469                                                 if ( '' == get_option('permalink_structure') || in_array($post->post_status, array('draft', 'pending')) )
470                                                         $output .= '<a href="' . get_permalink() . '&amp;page=' . $i . '">' . $link_before. $previouspagelink . $link_after . '</a>';
471                                                 else
472                                                         $output .= '<a href="' . trailingslashit(get_permalink()) . user_trailingslashit($i, 'single_paged') . '">' . $link_before. $previouspagelink . $link_after . '</a>';
473                                         }
474                                 }
475                                 $i = $page + 1;
476                                 if ( $i <= $numpages && $more ) {
477                                         if ( 1 == $i ) {
478                                                 $output .= '<a href="' . get_permalink() . '">' . $link_before. $nextpagelink . $link_after . '</a>';
479                                         } else {
480                                                 if ( '' == get_option('permalink_structure') || in_array($post->post_status, array('draft', 'pending')) )
481                                                         $output .= '<a href="' . get_permalink() . '&amp;page=' . $i . '">' . $link_before. $nextpagelink . $link_after . '</a>';
482                                                 else
483                                                         $output .= '<a href="' . trailingslashit(get_permalink()) . user_trailingslashit($i, 'single_paged') . '">' . $link_before. $nextpagelink . $link_after . '</a>';
484                                         }
485                                 }
486                                 $output .= $after;
487                         }
488                 }
489         }
490
491         if ( $echo )
492                 echo $output;
493
494         return $output;
495 }
496
497
498 //
499 // Post-meta: Custom per-post fields.
500 //
501
502 /**
503  * Retrieve post custom meta data field.
504  *
505  * @since 1.5.0
506  *
507  * @param string $key Meta data key name.
508  * @return string|array Array of values or single value, if only one element exists.
509  */
510 function post_custom( $key = '' ) {
511         $custom = get_post_custom();
512
513         if ( 1 == count($custom[$key]) )
514                 return $custom[$key][0];
515         else
516                 return $custom[$key];
517 }
518
519 /**
520  * Display list of post custom fields.
521  *
522  * @internal This will probably change at some point...
523  * @since 1.2.0
524  * @uses apply_filters() Calls 'the_meta_key' on list item HTML content, with key and value as separate parameters.
525  */
526 function the_meta() {
527         if ( $keys = get_post_custom_keys() ) {
528                 echo "<ul class='post-meta'>\n";
529                 foreach ( (array) $keys as $key ) {
530                         $keyt = trim($key);
531                         if ( '_' == $keyt{0} )
532                                 continue;
533                         $values = array_map('trim', get_post_custom_values($key));
534                         $value = implode($values,', ');
535                         echo apply_filters('the_meta_key', "<li><span class='post-meta-key'>$key:</span> $value</li>\n", $key, $value);
536                 }
537                 echo "</ul>\n";
538         }
539 }
540
541 //
542 // Pages
543 //
544
545 /**
546  * Retrieve or display list of pages as a dropdown (select list).
547  *
548  * @since 2.1.0
549  *
550  * @param array|string $args Optional. Override default arguments.
551  * @return string HTML content, if not displaying.
552  */
553 function wp_dropdown_pages($args = '') {
554         $defaults = array(
555                 'depth' => 0, 'child_of' => 0,
556                 'selected' => 0, 'echo' => 1,
557                 'name' => 'page_id', 'show_option_none' => '', 'show_option_no_change' => '',
558                 'option_none_value' => ''
559         );
560
561         $r = wp_parse_args( $args, $defaults );
562         extract( $r, EXTR_SKIP );
563
564         $pages = get_pages($r);
565         $output = '';
566
567         if ( ! empty($pages) ) {
568                 $output = "<select name=\"$name\" id=\"$name\">\n";
569                 if ( $show_option_no_change )
570                         $output .= "\t<option value=\"-1\">$show_option_no_change</option>";
571                 if ( $show_option_none )
572                         $output .= "\t<option value=\"$option_none_value\">$show_option_none</option>\n";
573                 $output .= walk_page_dropdown_tree($pages, $depth, $r);
574                 $output .= "</select>\n";
575         }
576
577         $output = apply_filters('wp_dropdown_pages', $output);
578
579         if ( $echo )
580                 echo $output;
581
582         return $output;
583 }
584
585 /**
586  * Retrieve or display list of pages in list (li) format.
587  *
588  * @since 1.5.0
589  *
590  * @param array|string $args Optional. Override default arguments.
591  * @return string HTML content, if not displaying.
592  */
593 function wp_list_pages($args = '') {
594         $defaults = array(
595                 'depth' => 0, 'show_date' => '',
596                 'date_format' => get_option('date_format'),
597                 'child_of' => 0, 'exclude' => '',
598                 'title_li' => __('Pages'), 'echo' => 1,
599                 'authors' => '', 'sort_column' => 'menu_order, post_title',
600                 'link_before' => '', 'link_after' => ''
601         );
602
603         $r = wp_parse_args( $args, $defaults );
604         extract( $r, EXTR_SKIP );
605
606         $output = '';
607         $current_page = 0;
608
609         // sanitize, mostly to keep spaces out
610         $r['exclude'] = preg_replace('/[^0-9,]/', '', $r['exclude']);
611
612         // Allow plugins to filter an array of excluded pages
613         $r['exclude'] = implode(',', apply_filters('wp_list_pages_excludes', explode(',', $r['exclude'])));
614
615         // Query pages.
616         $r['hierarchical'] = 0;
617         $pages = get_pages($r);
618
619         if ( !empty($pages) ) {
620                 if ( $r['title_li'] )
621                         $output .= '<li class="pagenav">' . $r['title_li'] . '<ul>';
622
623                 global $wp_query;
624                 if ( is_page() || $wp_query->is_posts_page )
625                         $current_page = $wp_query->get_queried_object_id();
626                 $output .= walk_page_tree($pages, $r['depth'], $current_page, $r);
627
628                 if ( $r['title_li'] )
629                         $output .= '</ul></li>';
630         }
631
632         $output = apply_filters('wp_list_pages', $output);
633
634         if ( $r['echo'] )
635                 echo $output;
636         else
637                 return $output;
638 }
639
640 /**
641  * Display or retrieve list of pages with optional home link.
642  *
643  * The arguments are listed below and part of the arguments are for {@link
644  * wp_list_pages()} function. Check that function for more info on those
645  * arguments.
646  *
647  * <ul>
648  * <li><strong>sort_column</strong> - How to sort the list of pages. Defaults
649  * to page title. Use column for posts table.</li>
650  * <li><strong>menu_class</strong> - Class to use for the div ID which contains
651  * the page list. Defaults to 'menu'.</li>
652  * <li><strong>echo</strong> - Whether to echo list or return it. Defaults to
653  * echo.</li>
654  * <li><strong>link_before</strong> - Text before show_home argument text.</li>
655  * <li><strong>link_after</strong> - Text after show_home argument text.</li>
656  * <li><strong>show_home</strong> - If you set this argument, then it will
657  * display the link to the home page. The show_home argument really just needs
658  * to be set to the value of the text of the link.</li>
659  * </ul>
660  *
661  * @since 2.7.0
662  *
663  * @param array|string $args
664  */
665 function wp_page_menu( $args = array() ) {
666         $defaults = array('sort_column' => 'post_title', 'menu_class' => 'menu', 'echo' => true, 'link_before' => '', 'link_after' => '');
667         $args = wp_parse_args( $args, $defaults );
668         $args = apply_filters( 'wp_page_menu_args', $args );
669
670         $menu = '';
671
672         $list_args = $args;
673
674         // Show Home in the menu
675         if ( isset($args['show_home']) && ! empty($args['show_home']) ) {
676                 if ( true === $args['show_home'] || '1' === $args['show_home'] || 1 === $args['show_home'] )
677                         $text = __('Home');
678                 else
679                         $text = $args['show_home'];
680                 $class = '';
681                 if ( is_front_page() && !is_paged() )
682                         $class = 'class="current_page_item"';
683                 $menu .= '<li ' . $class . '><a href="' . get_option('home') . '">' . $args['link_before'] . $text . $args['link_after'] . '</a></li>';
684                 // If the front page is a page, add it to the exclude list
685                 if (get_option('show_on_front') == 'page') {
686                         if ( !empty( $list_args['exclude'] ) ) {
687                                 $list_args['exclude'] .= ',';
688                         } else {
689                                 $list_args['exclude'] = '';
690                         }
691                         $list_args['exclude'] .= get_option('page_on_front');
692                 }
693         }
694
695         $list_args['echo'] = false;
696         $list_args['title_li'] = '';
697         $menu .= str_replace( array( "\r", "\n", "\t" ), '', wp_list_pages($list_args) );
698
699         if ( $menu )
700                 $menu = '<ul>' . $menu . '</ul>';
701
702         $menu = '<div class="' . $args['menu_class'] . '">' . $menu . "</div>\n";
703         $menu = apply_filters( 'wp_page_menu', $menu, $args );
704         if ( $args['echo'] )
705                 echo $menu;
706         else
707                 return $menu;
708 }
709
710 //
711 // Page helpers
712 //
713
714 /**
715  * Retrieve HTML list content for page list.
716  *
717  * @uses Walker_Page to create HTML list content.
718  * @since 2.1.0
719  * @see Walker_Page::walk() for parameters and return description.
720  */
721 function walk_page_tree($pages, $depth, $current_page, $r) {
722         $walker = new Walker_Page;
723         $args = array($pages, $depth, $r, $current_page);
724         return call_user_func_array(array(&$walker, 'walk'), $args);
725 }
726
727 /**
728  * Retrieve HTML dropdown (select) content for page list.
729  *
730  * @uses Walker_PageDropdown to create HTML dropdown content.
731  * @since 2.1.0
732  * @see Walker_PageDropdown::walk() for parameters and return description.
733  */
734 function walk_page_dropdown_tree() {
735         $walker = new Walker_PageDropdown;
736         $args = func_get_args();
737         return call_user_func_array(array(&$walker, 'walk'), $args);
738 }
739
740 //
741 // Attachments
742 //
743
744 /**
745  * Display an attachment page link using an image or icon.
746  *
747  * @since 2.0.0
748  *
749  * @param int $id Optional. Post ID.
750  * @param bool $fullsize Optional, default is false. Whether to use full size.
751  * @param bool $deprecated Deprecated. Not used.
752  * @param bool $permalink Optional, default is false. Whether to include permalink.
753  */
754 function the_attachment_link($id = 0, $fullsize = false, $deprecated = false, $permalink = false) {
755         if ( $fullsize )
756                 echo wp_get_attachment_link($id, 'full', $permalink);
757         else
758                 echo wp_get_attachment_link($id, 'thumbnail', $permalink);
759 }
760
761 /**
762  * Retrieve an attachment page link using an image or icon, if possible.
763  *
764  * @since 2.5.0
765  * @uses apply_filters() Calls 'wp_get_attachment_link' filter on HTML content with same parameters as function.
766  *
767  * @param int $id Optional. Post ID.
768  * @param string $size Optional. Image size.
769  * @param bool $permalink Optional, default is false. Whether to add permalink to image.
770  * @param bool $icon Optional, default is false. Whether to include icon.
771  * @return string HTML content.
772  */
773 function wp_get_attachment_link($id = 0, $size = 'thumbnail', $permalink = false, $icon = false) {
774         $id = intval($id);
775         $_post = & get_post( $id );
776
777         if ( ('attachment' != $_post->post_type) || !$url = wp_get_attachment_url($_post->ID) )
778                 return __('Missing Attachment');
779
780         if ( $permalink )
781                 $url = get_attachment_link($_post->ID);
782
783         $post_title = attribute_escape($_post->post_title);
784
785         $link_text = wp_get_attachment_image($id, $size, $icon);
786         if ( !$link_text )
787                 $link_text = $_post->post_title;
788
789         return apply_filters( 'wp_get_attachment_link', "<a href='$url' title='$post_title'>$link_text</a>", $id, $size, $permalink, $icon );
790 }
791
792 /**
793  * Retrieve HTML content of attachment image with link.
794  *
795  * @since 2.0.0
796  * @deprecated Use {@link wp_get_attachment_link()}
797  * @see wp_get_attachment_link() Use instead.
798  *
799  * @param int $id Optional. Post ID.
800  * @param bool $fullsize Optional, default is false. Whether to use full size image.
801  * @param array $max_dims Optional. Max image dimensions.
802  * @param bool $permalink Optional, default is false. Whether to include permalink to image.
803  * @return string
804  */
805 function get_the_attachment_link($id = 0, $fullsize = false, $max_dims = false, $permalink = false) {
806         $id = (int) $id;
807         $_post = & get_post($id);
808
809         if ( ('attachment' != $_post->post_type) || !$url = wp_get_attachment_url($_post->ID) )
810                 return __('Missing Attachment');
811
812         if ( $permalink )
813                 $url = get_attachment_link($_post->ID);
814
815         $post_title = attribute_escape($_post->post_title);
816
817         $innerHTML = get_attachment_innerHTML($_post->ID, $fullsize, $max_dims);
818         return "<a href='$url' title='$post_title'>$innerHTML</a>";
819 }
820
821 /**
822  * Retrieve icon URL and Path.
823  *
824  * @since 2.1.0
825  * @deprecated Use {@link wp_get_attachment_image_src()}
826  * @see wp_get_attachment_image_src() Use instead.
827  *
828  * @param int $id Optional. Post ID.
829  * @param bool $fullsize Optional, default to false. Whether to have full image.
830  * @return array Icon URL and full path to file, respectively.
831  */
832 function get_attachment_icon_src( $id = 0, $fullsize = false ) {
833         $id = (int) $id;
834         if ( !$post = & get_post($id) )
835                 return false;
836
837         $file = get_attached_file( $post->ID );
838
839         if ( !$fullsize && $src = wp_get_attachment_thumb_url( $post->ID ) ) {
840                 // We have a thumbnail desired, specified and existing
841
842                 $src_file = basename($src);
843                 $class = 'attachmentthumb';
844         } elseif ( wp_attachment_is_image( $post->ID ) ) {
845                 // We have an image without a thumbnail
846
847                 $src = wp_get_attachment_url( $post->ID );
848                 $src_file = & $file;
849                 $class = 'attachmentimage';
850         } elseif ( $src = wp_mime_type_icon( $post->ID ) ) {
851                 // No thumb, no image. We'll look for a mime-related icon instead.
852
853                 $icon_dir = apply_filters( 'icon_dir', get_template_directory() . '/images' );
854                 $src_file = $icon_dir . '/' . basename($src);
855         }
856
857         if ( !isset($src) || !$src )
858                 return false;
859
860         return array($src, $src_file);
861 }
862
863 /**
864  * Retrieve HTML content of icon attachment image element.
865  *
866  * @since 2.0.0
867  * @deprecated Use {@link wp_get_attachment_image()}
868  * @see wp_get_attachment_image() Use instead of.
869  *
870  * @param int $id Optional. Post ID.
871  * @param bool $fullsize Optional, default to false. Whether to have full size image.
872  * @param array $max_dims Optional. Dimensions of image.
873  * @return string HTML content.
874  */
875 function get_attachment_icon( $id = 0, $fullsize = false, $max_dims = false ) {
876         $id = (int) $id;
877         if ( !$post = & get_post($id) )
878                 return false;
879
880         if ( !$src = get_attachment_icon_src( $post->ID, $fullsize ) )
881                 return false;
882
883         list($src, $src_file) = $src;
884
885         // Do we need to constrain the image?
886         if ( ($max_dims = apply_filters('attachment_max_dims', $max_dims)) && file_exists($src_file) ) {
887
888                 $imagesize = getimagesize($src_file);
889
890                 if (($imagesize[0] > $max_dims[0]) || $imagesize[1] > $max_dims[1] ) {
891                         $actual_aspect = $imagesize[0] / $imagesize[1];
892                         $desired_aspect = $max_dims[0] / $max_dims[1];
893
894                         if ( $actual_aspect >= $desired_aspect ) {
895                                 $height = $actual_aspect * $max_dims[0];
896                                 $constraint = "width='{$max_dims[0]}' ";
897                                 $post->iconsize = array($max_dims[0], $height);
898                         } else {
899                                 $width = $max_dims[1] / $actual_aspect;
900                                 $constraint = "height='{$max_dims[1]}' ";
901                                 $post->iconsize = array($width, $max_dims[1]);
902                         }
903                 } else {
904                         $post->iconsize = array($imagesize[0], $imagesize[1]);
905                         $constraint = '';
906                 }
907         } else {
908                 $constraint = '';
909         }
910
911         $post_title = attribute_escape($post->post_title);
912
913         $icon = "<img src='$src' title='$post_title' alt='$post_title' $constraint/>";
914
915         return apply_filters( 'attachment_icon', $icon, $post->ID );
916 }
917
918 /**
919  * Retrieve HTML content of image element.
920  *
921  * @since 2.0.0
922  * @deprecated Use {@link wp_get_attachment_image()}
923  * @see wp_get_attachment_image() Use instead.
924  *
925  * @param int $id Optional. Post ID.
926  * @param bool $fullsize Optional, default to false. Whether to have full size image.
927  * @param array $max_dims Optional. Dimensions of image.
928  * @return string
929  */
930 function get_attachment_innerHTML($id = 0, $fullsize = false, $max_dims = false) {
931         $id = (int) $id;
932         if ( !$post = & get_post($id) )
933                 return false;
934
935         if ( $innerHTML = get_attachment_icon($post->ID, $fullsize, $max_dims))
936                 return $innerHTML;
937
938
939         $innerHTML = attribute_escape($post->post_title);
940
941         return apply_filters('attachment_innerHTML', $innerHTML, $post->ID);
942 }
943
944 /**
945  * Wrap attachment in <<p>> element before content.
946  *
947  * @since 2.0.0
948  * @uses apply_filters() Calls 'prepend_attachment' hook on HTML content.
949  *
950  * @param string $content
951  * @return string
952  */
953 function prepend_attachment($content) {
954         global $post;
955
956         if ( empty($post->post_type) || $post->post_type != 'attachment' )
957                 return $content;
958
959         $p = '<p class="attachment">';
960         // show the medium sized image representation of the attachment if available, and link to the raw file
961         $p .= wp_get_attachment_link(0, 'medium', false);
962         $p .= '</p>';
963         $p = apply_filters('prepend_attachment', $p);
964
965         return "$p\n$content";
966 }
967
968 //
969 // Misc
970 //
971
972 /**
973  * Retrieve protected post password form content.
974  *
975  * @since 1.0.0
976  * @uses apply_filters() Calls 'the_password_form' filter on output.
977  *
978  * @return string HTML content for password form for password protected post.
979  */
980 function get_the_password_form() {
981         global $post;
982         $label = 'pwbox-'.(empty($post->ID) ? rand() : $post->ID);
983         $output = '<form action="' . get_option('siteurl') . '/wp-pass.php" method="post">
984         <p>' . __("This post is password protected. To view it please enter your password below:") . '</p>
985         <p><label for="' . $label . '">' . __("Password:") . ' <input name="post_password" id="' . $label . '" type="password" size="20" /></label> <input type="submit" name="Submit" value="' . __("Submit") . '" /></p>
986         </form>
987         ';
988         return apply_filters('the_password_form', $output);
989 }
990
991 /**
992  * Whether currently in a page template.
993  *
994  * This template tag allows you to determine whether or not you are in a page
995  * template. You can optional provide a template name and then the check will be
996  * specific to that template.
997  *
998  * @since 2.5.0
999  * @uses $wp_query
1000  *
1001  * @param string $template The specific template name if specific matching is required.
1002  * @return bool False on failure, true if success.
1003  */
1004 function is_page_template($template = '') {
1005         if (!is_page()) {
1006                 return false;
1007         }
1008
1009         global $wp_query;
1010
1011         $page = $wp_query->get_queried_object();
1012         $custom_fields = get_post_custom_values('_wp_page_template',$page->ID);
1013         $page_template = $custom_fields[0];
1014
1015         // We have no argument passed so just see if a page_template has been specified
1016         if ( empty( $template ) ) {
1017                 if (!empty( $page_template ) ) {
1018                         return true;
1019                 }
1020         } elseif ( $template == $page_template) {
1021                 return true;
1022         }
1023
1024         return false;
1025 }
1026
1027 /**
1028  * Retrieve formatted date timestamp of a revision (linked to that revisions's page).
1029  *
1030  * @package WordPress
1031  * @subpackage Post_Revisions
1032  * @since 2.6.0
1033  *
1034  * @uses date_i18n()
1035  *
1036  * @param int|object $revision Revision ID or revision object.
1037  * @param bool $link Optional, default is true. Link to revisions's page?
1038  * @return string i18n formatted datetimestamp or localized 'Current Revision'.
1039  */
1040 function wp_post_revision_title( $revision, $link = true ) {
1041         if ( !$revision = get_post( $revision ) )
1042                 return $revision;
1043
1044         if ( !in_array( $revision->post_type, array( 'post', 'page', 'revision' ) ) )
1045                 return false;
1046
1047         $datef = _c( 'j F, Y @ G:i|revision date format');
1048         $autosavef = __( '%s [Autosave]' );
1049         $currentf  = __( '%s [Current Revision]' );
1050
1051         $date = date_i18n( $datef, strtotime( $revision->post_modified ) );
1052         if ( $link && current_user_can( 'edit_post', $revision->ID ) && $link = get_edit_post_link( $revision->ID ) )
1053                 $date = "<a href='$link'>$date</a>";
1054
1055         if ( !wp_is_post_revision( $revision ) )
1056                 $date = sprintf( $currentf, $date );
1057         elseif ( wp_is_post_autosave( $revision ) )
1058                 $date = sprintf( $autosavef, $date );
1059
1060         return $date;
1061 }
1062
1063 /**
1064  * Display list of a post's revisions.
1065  *
1066  * Can output either a UL with edit links or a TABLE with diff interface, and
1067  * restore action links.
1068  *
1069  * Second argument controls parameters:
1070  *   (bool)   parent : include the parent (the "Current Revision") in the list.
1071  *   (string) format : 'list' or 'form-table'.  'list' outputs UL, 'form-table'
1072  *                     outputs TABLE with UI.
1073  *   (int)    right  : what revision is currently being viewed - used in
1074  *                     form-table format.
1075  *   (int)    left   : what revision is currently being diffed against right -
1076  *                     used in form-table format.
1077  *
1078  * @package WordPress
1079  * @subpackage Post_Revisions
1080  * @since 2.6.0
1081  *
1082  * @uses wp_get_post_revisions()
1083  * @uses wp_post_revision_title()
1084  * @uses get_edit_post_link()
1085  * @uses get_author_name()
1086  *
1087  * @todo split into two functions (list, form-table) ?
1088  *
1089  * @param int|object $post_id Post ID or post object.
1090  * @param string|array $args See description {@link wp_parse_args()}.
1091  * @return null
1092  */
1093 function wp_list_post_revisions( $post_id = 0, $args = null ) {
1094         if ( !$post = get_post( $post_id ) )
1095                 return;
1096
1097         $defaults = array( 'parent' => false, 'right' => false, 'left' => false, 'format' => 'list', 'type' => 'all' );
1098         extract( wp_parse_args( $args, $defaults ), EXTR_SKIP );
1099
1100         switch ( $type ) {
1101         case 'autosave' :
1102                 if ( !$autosave = wp_get_post_autosave( $post->ID ) )
1103                         return;
1104                 $revisions = array( $autosave );
1105                 break;
1106         case 'revision' : // just revisions - remove autosave later
1107         case 'all' :
1108         default :
1109                 if ( !$revisions = wp_get_post_revisions( $post->ID ) )
1110                         return;
1111                 break;
1112         }
1113
1114         $titlef = _c( '%1$s by %2$s|post revision 1:datetime, 2:name' );
1115
1116         if ( $parent )
1117                 array_unshift( $revisions, $post );
1118
1119         $rows = '';
1120         $class = false;
1121         $can_edit_post = current_user_can( 'edit_post', $post->ID );
1122         foreach ( $revisions as $revision ) {
1123                 if ( !current_user_can( 'read_post', $revision->ID ) )
1124                         continue;
1125                 if ( 'revision' === $type && wp_is_post_autosave( $revision ) )
1126                         continue;
1127
1128                 $date = wp_post_revision_title( $revision );
1129                 $name = get_author_name( $revision->post_author );
1130
1131                 if ( 'form-table' == $format ) {
1132                         if ( $left )
1133                                 $left_checked = $left == $revision->ID ? ' checked="checked"' : '';
1134                         else
1135                                 $left_checked = $right_checked ? ' checked="checked"' : ''; // [sic] (the next one)
1136                         $right_checked = $right == $revision->ID ? ' checked="checked"' : '';
1137
1138                         $class = $class ? '' : " class='alternate'";
1139
1140                         if ( $post->ID != $revision->ID && $can_edit_post )
1141                                 $actions = '<a href="' . wp_nonce_url( add_query_arg( array( 'revision' => $revision->ID, 'diff' => false, 'action' => 'restore' ) ), "restore-post_$post->ID|$revision->ID" ) . '">' . __( 'Restore' ) . '</a>';
1142                         else
1143                                 $actions = '';
1144
1145                         $rows .= "<tr$class>\n";
1146                         $rows .= "\t<th style='white-space: nowrap' scope='row'><input type='radio' name='left' value='$revision->ID'$left_checked /><input type='radio' name='right' value='$revision->ID'$right_checked /></th>\n";
1147                         $rows .= "\t<td>$date</td>\n";
1148                         $rows .= "\t<td>$name</td>\n";
1149                         $rows .= "\t<td class='action-links'>$actions</td>\n";
1150                         $rows .= "</tr>\n";
1151                 } else {
1152                         $title = sprintf( $titlef, $date, $name );
1153                         $rows .= "\t<li>$title</li>\n";
1154                 }
1155         }
1156
1157         if ( 'form-table' == $format ) : ?>
1158
1159 <form action="revision.php" method="get">
1160
1161 <div class="tablenav">
1162         <div class="alignleft">
1163                 <input type="submit" class="button-secondary" value="<?php _e( 'Compare Revisions' ); ?>" />
1164                 <input type="hidden" name="action" value="diff" />
1165         </div>
1166 </div>
1167
1168 <br class="clear" />
1169
1170 <table class="widefat post-revisions" cellspacing="0">
1171         <col />
1172         <col style="width: 33%" />
1173         <col style="width: 33%" />
1174         <col style="width: 33%" />
1175 <thead>
1176 <tr>
1177         <th scope="col"></th>
1178         <th scope="col"><?php _e( 'Date Created' ); ?></th>
1179         <th scope="col"><?php _e( 'Author' ); ?></th>
1180         <th scope="col" class="action-links"><?php _e( 'Actions' ); ?></th>
1181 </tr>
1182 </thead>
1183 <tbody>
1184
1185 <?php echo $rows; ?>
1186
1187 </tbody>
1188 </table>
1189
1190 </form>
1191
1192 <?php
1193         else :
1194                 echo "<ul class='post-revisions'>\n";
1195                 echo $rows;
1196                 echo "</ul>";
1197         endif;
1198
1199 }