Wordpress 2.9.2-scripts
[autoinstalls/wordpress.git] / wp-includes / link-template.php
1 <?php
2 /**
3  * WordPress Link Template Functions
4  *
5  * @package WordPress
6  * @subpackage Template
7  */
8
9 /**
10  * Display the permalink for the current post.
11  *
12  * @since 1.2.0
13  * @uses apply_filters() Calls 'the_permalink' filter on the permalink string.
14  */
15 function the_permalink() {
16         echo apply_filters('the_permalink', get_permalink());
17 }
18
19 /**
20  * Retrieve trailing slash string, if blog set for adding trailing slashes.
21  *
22  * Conditionally adds a trailing slash if the permalink structure has a trailing
23  * slash, strips the trailing slash if not. The string is passed through the
24  * 'user_trailingslashit' filter. Will remove trailing slash from string, if
25  * blog is not set to have them.
26  *
27  * @since 2.2.0
28  * @uses $wp_rewrite
29  *
30  * @param $string String a URL with or without a trailing slash.
31  * @param $type_of_url String the type of URL being considered (e.g. single, category, etc) for use in the filter.
32  * @return string
33  */
34 function user_trailingslashit($string, $type_of_url = '') {
35         global $wp_rewrite;
36         if ( $wp_rewrite->use_trailing_slashes )
37                 $string = trailingslashit($string);
38         else
39                 $string = untrailingslashit($string);
40
41         // Note that $type_of_url can be one of following:
42         // single, single_trackback, single_feed, single_paged, feed, category, page, year, month, day, paged
43         $string = apply_filters('user_trailingslashit', $string, $type_of_url);
44         return $string;
45 }
46
47 /**
48  * Display permalink anchor for current post.
49  *
50  * The permalink mode title will use the post title for the 'a' element 'id'
51  * attribute. The id mode uses 'post-' with the post ID for the 'id' attribute.
52  *
53  * @since 0.71
54  *
55  * @param string $mode Permalink mode can be either 'title', 'id', or default, which is 'id'.
56  */
57 function permalink_anchor($mode = 'id') {
58         global $post;
59         switch ( strtolower($mode) ) {
60                 case 'title':
61                         $title = sanitize_title($post->post_title) . '-' . $post->ID;
62                         echo '<a id="'.$title.'"></a>';
63                         break;
64                 case 'id':
65                 default:
66                         echo '<a id="post-' . $post->ID . '"></a>';
67                         break;
68         }
69 }
70
71 /**
72  * Retrieve full permalink for current post or post ID.
73  *
74  * @since 1.0.0
75  *
76  * @param int $id Optional. Post ID.
77  * @param bool $leavename Optional, defaults to false. Whether to keep post name or page name.
78  * @return string
79  */
80 function get_permalink($id = 0, $leavename = false) {
81         $rewritecode = array(
82                 '%year%',
83                 '%monthnum%',
84                 '%day%',
85                 '%hour%',
86                 '%minute%',
87                 '%second%',
88                 $leavename? '' : '%postname%',
89                 '%post_id%',
90                 '%category%',
91                 '%author%',
92                 $leavename? '' : '%pagename%',
93         );
94
95         if ( is_object($id) && isset($id->filter) && 'sample' == $id->filter ) {
96                 $post = $id;
97                 $sample = true;
98         } else {
99                 $post = &get_post($id);
100                 $sample = false;
101         }
102
103         if ( empty($post->ID) ) return false;
104
105         if ( $post->post_type == 'page' )
106                 return get_page_link($post->ID, $leavename, $sample);
107         elseif ($post->post_type == 'attachment')
108                 return get_attachment_link($post->ID);
109
110         $permalink = get_option('permalink_structure');
111
112         if ( '' != $permalink && !in_array($post->post_status, array('draft', 'pending')) ) {
113                 $unixtime = strtotime($post->post_date);
114
115                 $category = '';
116                 if ( strpos($permalink, '%category%') !== false ) {
117                         $cats = get_the_category($post->ID);
118                         if ( $cats ) {
119                                 usort($cats, '_usort_terms_by_ID'); // order by ID
120                                 $category = $cats[0]->slug;
121                                 if ( $parent = $cats[0]->parent )
122                                         $category = get_category_parents($parent, false, '/', true) . $category;
123                         }
124                         // show default category in permalinks, without
125                         // having to assign it explicitly
126                         if ( empty($category) ) {
127                                 $default_category = get_category( get_option( 'default_category' ) );
128                                 $category = is_wp_error( $default_category ) ? '' : $default_category->slug;
129                         }
130                 }
131
132                 $author = '';
133                 if ( strpos($permalink, '%author%') !== false ) {
134                         $authordata = get_userdata($post->post_author);
135                         $author = $authordata->user_nicename;
136                 }
137
138                 $date = explode(" ",date('Y m d H i s', $unixtime));
139                 $rewritereplace =
140                 array(
141                         $date[0],
142                         $date[1],
143                         $date[2],
144                         $date[3],
145                         $date[4],
146                         $date[5],
147                         $post->post_name,
148                         $post->ID,
149                         $category,
150                         $author,
151                         $post->post_name,
152                 );
153                 $permalink = get_option('home') . str_replace($rewritecode, $rewritereplace, $permalink);
154                 $permalink = user_trailingslashit($permalink, 'single');
155                 return apply_filters('post_link', $permalink, $post, $leavename);
156         } else { // if they're not using the fancy permalink option
157                 $permalink = trailingslashit(get_option('home')) . '?p=' . $post->ID;
158                 return apply_filters('post_link', $permalink, $post, $leavename);
159         }
160 }
161
162 /**
163  * Retrieve permalink from post ID.
164  *
165  * @since 1.0.0
166  *
167  * @param int $post_id Optional. Post ID.
168  * @param mixed $deprecated Not used.
169  * @return string
170  */
171 function post_permalink($post_id = 0, $deprecated = '') {
172         return get_permalink($post_id);
173 }
174
175 /**
176  * Retrieve the permalink for current page or page ID.
177  *
178  * Respects page_on_front. Use this one.
179  *
180  * @since 1.5.0
181  *
182  * @param int $id Optional. Post ID.
183  * @param bool $leavename Optional, defaults to false. Whether to keep page name.
184  * @param bool $sample Optional, defaults to false. Is it a sample permalink.
185  * @return string
186  */
187 function get_page_link( $id = false, $leavename = false, $sample = false ) {
188         global $post;
189
190         $id = (int) $id;
191         if ( !$id )
192                 $id = (int) $post->ID;
193
194         if ( 'page' == get_option('show_on_front') && $id == get_option('page_on_front') )
195                 $link = get_option('home');
196         else
197                 $link = _get_page_link( $id , $leavename, $sample );
198
199         return apply_filters('page_link', $link, $id);
200 }
201
202 /**
203  * Retrieve the page permalink.
204  *
205  * Ignores page_on_front. Internal use only.
206  *
207  * @since 2.1.0
208  * @access private
209  *
210  * @param int $id Optional. Post ID.
211  * @param bool $leavename Optional. Leave name.
212  * @param bool $sample Optional. Sample permalink.
213  * @return string
214  */
215 function _get_page_link( $id = false, $leavename = false, $sample = false ) {
216         global $post, $wp_rewrite;
217
218         if ( !$id )
219                 $id = (int) $post->ID;
220         else
221                 $post = &get_post($id);
222
223         $pagestruct = $wp_rewrite->get_page_permastruct();
224
225         if ( '' != $pagestruct && ( ( isset($post->post_status) && 'draft' != $post->post_status && 'pending' != $post->post_status ) || $sample ) ) {
226                 $link = get_page_uri($id);
227                 $link = ( $leavename ) ? $pagestruct : str_replace('%pagename%', $link, $pagestruct);
228                 $link = trailingslashit(get_option('home')) . "$link";
229                 $link = user_trailingslashit($link, 'page');
230         } else {
231                 $link = trailingslashit(get_option('home')) . "?page_id=$id";
232         }
233
234         return apply_filters( '_get_page_link', $link, $id );
235 }
236
237 /**
238  * Retrieve permalink for attachment.
239  *
240  * This can be used in the WordPress Loop or outside of it.
241  *
242  * @since 2.0.0
243  *
244  * @param int $id Optional. Post ID.
245  * @return string
246  */
247 function get_attachment_link($id = false) {
248         global $post, $wp_rewrite;
249
250         $link = false;
251
252         if (! $id) {
253                 $id = (int) $post->ID;
254         }
255
256         $object = get_post($id);
257         if ( $wp_rewrite->using_permalinks() && ($object->post_parent > 0) && ($object->post_parent != $id) ) {
258                 $parent = get_post($object->post_parent);
259                 if ( 'page' == $parent->post_type )
260                         $parentlink = _get_page_link( $object->post_parent ); // Ignores page_on_front
261                 else
262                         $parentlink = get_permalink( $object->post_parent );
263                 if ( is_numeric($object->post_name) || false !== strpos(get_option('permalink_structure'), '%category%') )
264                         $name = 'attachment/' . $object->post_name; // <permalink>/<int>/ is paged so we use the explicit attachment marker
265                 else
266                         $name = $object->post_name;
267                 if (strpos($parentlink, '?') === false)
268                         $link = user_trailingslashit( trailingslashit($parentlink) . $name );
269         }
270
271         if (! $link ) {
272                 $link = trailingslashit(get_bloginfo('url')) . "?attachment_id=$id";
273         }
274
275         return apply_filters('attachment_link', $link, $id);
276 }
277
278 /**
279  * Retrieve the permalink for the year archives.
280  *
281  * @since 1.5.0
282  *
283  * @param int|bool $year False for current year or year for permalink.
284  * @return string
285  */
286 function get_year_link($year) {
287         global $wp_rewrite;
288         if ( !$year )
289                 $year = gmdate('Y', time()+(get_option('gmt_offset') * 3600));
290         $yearlink = $wp_rewrite->get_year_permastruct();
291         if ( !empty($yearlink) ) {
292                 $yearlink = str_replace('%year%', $year, $yearlink);
293                 return apply_filters('year_link', get_option('home') . user_trailingslashit($yearlink, 'year'), $year);
294         } else {
295                 return apply_filters('year_link', trailingslashit(get_option('home')) . '?m=' . $year, $year);
296         }
297 }
298
299 /**
300  * Retrieve the permalink for the month archives with year.
301  *
302  * @since 1.0.0
303  *
304  * @param bool|int $year False for current year. Integer of year.
305  * @param bool|int $month False for current month. Integer of month.
306  * @return string
307  */
308 function get_month_link($year, $month) {
309         global $wp_rewrite;
310         if ( !$year )
311                 $year = gmdate('Y', time()+(get_option('gmt_offset') * 3600));
312         if ( !$month )
313                 $month = gmdate('m', time()+(get_option('gmt_offset') * 3600));
314         $monthlink = $wp_rewrite->get_month_permastruct();
315         if ( !empty($monthlink) ) {
316                 $monthlink = str_replace('%year%', $year, $monthlink);
317                 $monthlink = str_replace('%monthnum%', zeroise(intval($month), 2), $monthlink);
318                 return apply_filters('month_link', get_option('home') . user_trailingslashit($monthlink, 'month'), $year, $month);
319         } else {
320                 return apply_filters('month_link', trailingslashit(get_option('home')) . '?m=' . $year . zeroise($month, 2), $year, $month);
321         }
322 }
323
324 /**
325  * Retrieve the permalink for the day archives with year and month.
326  *
327  * @since 1.0.0
328  *
329  * @param bool|int $year False for current year. Integer of year.
330  * @param bool|int $month False for current month. Integer of month.
331  * @param bool|int $day False for current day. Integer of day.
332  * @return string
333  */
334 function get_day_link($year, $month, $day) {
335         global $wp_rewrite;
336         if ( !$year )
337                 $year = gmdate('Y', time()+(get_option('gmt_offset') * 3600));
338         if ( !$month )
339                 $month = gmdate('m', time()+(get_option('gmt_offset') * 3600));
340         if ( !$day )
341                 $day = gmdate('j', time()+(get_option('gmt_offset') * 3600));
342
343         $daylink = $wp_rewrite->get_day_permastruct();
344         if ( !empty($daylink) ) {
345                 $daylink = str_replace('%year%', $year, $daylink);
346                 $daylink = str_replace('%monthnum%', zeroise(intval($month), 2), $daylink);
347                 $daylink = str_replace('%day%', zeroise(intval($day), 2), $daylink);
348                 return apply_filters('day_link', get_option('home') . user_trailingslashit($daylink, 'day'), $year, $month, $day);
349         } else {
350                 return apply_filters('day_link', trailingslashit(get_option('home')) . '?m=' . $year . zeroise($month, 2) . zeroise($day, 2), $year, $month, $day);
351         }
352 }
353
354 /**
355  * Retrieve the permalink for the feed type.
356  *
357  * @since 1.5.0
358  *
359  * @param string $feed Optional, defaults to default feed. Feed type.
360  * @return string
361  */
362 function get_feed_link($feed = '') {
363         global $wp_rewrite;
364
365         $permalink = $wp_rewrite->get_feed_permastruct();
366         if ( '' != $permalink ) {
367                 if ( false !== strpos($feed, 'comments_') ) {
368                         $feed = str_replace('comments_', '', $feed);
369                         $permalink = $wp_rewrite->get_comment_feed_permastruct();
370                 }
371
372                 if ( get_default_feed() == $feed )
373                         $feed = '';
374
375                 $permalink = str_replace('%feed%', $feed, $permalink);
376                 $permalink = preg_replace('#/+#', '/', "/$permalink");
377                 $output =  get_option('home') . user_trailingslashit($permalink, 'feed');
378         } else {
379                 if ( empty($feed) )
380                         $feed = get_default_feed();
381
382                 if ( false !== strpos($feed, 'comments_') )
383                         $feed = str_replace('comments_', 'comments-', $feed);
384
385                 $output = trailingslashit(get_option('home')) . "?feed={$feed}";
386         }
387
388         return apply_filters('feed_link', $output, $feed);
389 }
390
391 /**
392  * Retrieve the permalink for the post comments feed.
393  *
394  * @since 2.2.0
395  *
396  * @param int $post_id Optional. Post ID.
397  * @param string $feed Optional. Feed type.
398  * @return string
399  */
400 function get_post_comments_feed_link($post_id = '', $feed = '') {
401         global $id;
402
403         if ( empty($post_id) )
404                 $post_id = (int) $id;
405
406         if ( empty($feed) )
407                 $feed = get_default_feed();
408
409         if ( '' != get_option('permalink_structure') ) {
410                 $url = trailingslashit( get_permalink($post_id) ) . 'feed';
411                 if ( $feed != get_default_feed() )
412                         $url .= "/$feed";
413                 $url = user_trailingslashit($url, 'single_feed');
414         } else {
415                 $type = get_post_field('post_type', $post_id);
416                 if ( 'page' == $type )
417                         $url = trailingslashit(get_option('home')) . "?feed=$feed&amp;page_id=$post_id";
418                 else
419                         $url = trailingslashit(get_option('home')) . "?feed=$feed&amp;p=$post_id";
420         }
421
422         return apply_filters('post_comments_feed_link', $url);
423 }
424
425 /**
426  * Display the comment feed link for a post.
427  *
428  * Prints out the comment feed link for a post. Link text is placed in the
429  * anchor. If no link text is specified, default text is used. If no post ID is
430  * specified, the current post is used.
431  *
432  * @package WordPress
433  * @subpackage Feed
434  * @since 2.5.0
435  *
436  * @param string $link_text Descriptive text.
437  * @param int $post_id Optional post ID.  Default to current post.
438  * @param string $feed Optional. Feed format.
439  * @return string Link to the comment feed for the current post.
440 */
441 function post_comments_feed_link( $link_text = '', $post_id = '', $feed = '' ) {
442         $url = get_post_comments_feed_link($post_id, $feed);
443         if ( empty($link_text) )
444                 $link_text = __('Comments Feed');
445
446         echo apply_filters( 'post_comments_feed_link_html', "<a href='$url'>$link_text</a>", $post_id, $feed );
447 }
448
449 /**
450  * Retrieve the feed link for a given author.
451  *
452  * Returns a link to the feed for all posts by a given author. A specific feed
453  * can be requested or left blank to get the default feed.
454  *
455  * @package WordPress
456  * @subpackage Feed
457  * @since 2.5.0
458  *
459  * @param int $author_id ID of an author.
460  * @param string $feed Optional. Feed type.
461  * @return string Link to the feed for the author specified by $author_id.
462 */
463 function get_author_feed_link( $author_id, $feed = '' ) {
464         $author_id = (int) $author_id;
465         $permalink_structure = get_option('permalink_structure');
466
467         if ( empty($feed) )
468                 $feed = get_default_feed();
469
470         if ( '' == $permalink_structure ) {
471                 $link = trailingslashit(get_option('home')) . "?feed=$feed&amp;author=" . $author_id;
472         } else {
473                 $link = get_author_posts_url($author_id);
474                 if ( $feed == get_default_feed() )
475                         $feed_link = 'feed';
476                 else
477                         $feed_link = "feed/$feed";
478
479                 $link = trailingslashit($link) . user_trailingslashit($feed_link, 'feed');
480         }
481
482         $link = apply_filters('author_feed_link', $link, $feed);
483
484         return $link;
485 }
486
487 /**
488  * Retrieve the feed link for a category.
489  *
490  * Returns a link to the feed for all post in a given category. A specific feed
491  * can be requested or left blank to get the default feed.
492  *
493  * @package WordPress
494  * @subpackage Feed
495  * @since 2.5.0
496  *
497  * @param int $cat_id ID of a category.
498  * @param string $feed Optional. Feed type.
499  * @return string Link to the feed for the category specified by $cat_id.
500 */
501 function get_category_feed_link($cat_id, $feed = '') {
502         $cat_id = (int) $cat_id;
503
504         $category = get_category($cat_id);
505
506         if ( empty($category) || is_wp_error($category) )
507                 return false;
508
509         if ( empty($feed) )
510                 $feed = get_default_feed();
511
512         $permalink_structure = get_option('permalink_structure');
513
514         if ( '' == $permalink_structure ) {
515                 $link = trailingslashit(get_option('home')) . "?feed=$feed&amp;cat=" . $cat_id;
516         } else {
517                 $link = get_category_link($cat_id);
518                 if( $feed == get_default_feed() )
519                         $feed_link = 'feed';
520                 else
521                         $feed_link = "feed/$feed";
522
523                 $link = trailingslashit($link) . user_trailingslashit($feed_link, 'feed');
524         }
525
526         $link = apply_filters('category_feed_link', $link, $feed);
527
528         return $link;
529 }
530
531 /**
532  * Retrieve permalink for feed of tag.
533  *
534  * @since 2.3.0
535  *
536  * @param int $tag_id Tag ID.
537  * @param string $feed Optional. Feed type.
538  * @return string
539  */
540 function get_tag_feed_link($tag_id, $feed = '') {
541         $tag_id = (int) $tag_id;
542
543         $tag = get_tag($tag_id);
544
545         if ( empty($tag) || is_wp_error($tag) )
546                 return false;
547
548         $permalink_structure = get_option('permalink_structure');
549
550         if ( empty($feed) )
551                 $feed = get_default_feed();
552
553         if ( '' == $permalink_structure ) {
554                 $link = trailingslashit(get_option('home')) . "?feed=$feed&amp;tag=" . $tag->slug;
555         } else {
556                 $link = get_tag_link($tag->term_id);
557                 if ( $feed == get_default_feed() )
558                         $feed_link = 'feed';
559                 else
560                         $feed_link = "feed/$feed";
561                 $link = trailingslashit($link) . user_trailingslashit($feed_link, 'feed');
562         }
563
564         $link = apply_filters('tag_feed_link', $link, $feed);
565
566         return $link;
567 }
568
569 /**
570  * Retrieve edit tag link.
571  *
572  * @since 2.7.0
573  *
574  * @param int $tag_id Tag ID
575  * @return string
576  */
577 function get_edit_tag_link( $tag_id = 0, $taxonomy = 'post_tag' ) {
578         $tag = get_term($tag_id, $taxonomy);
579
580         if ( !current_user_can('manage_categories') )
581                 return;
582
583         $location = admin_url('edit-tags.php?action=edit&amp;taxonomy=' . $taxonomy . '&amp;tag_ID=' . $tag->term_id);
584         return apply_filters( 'get_edit_tag_link', $location );
585 }
586
587 /**
588  * Display or retrieve edit tag link with formatting.
589  *
590  * @since 2.7.0
591  *
592  * @param string $link Optional. Anchor text.
593  * @param string $before Optional. Display before edit link.
594  * @param string $after Optional. Display after edit link.
595  * @param int|object $tag Tag object or ID
596  * @return string|null HTML content, if $echo is set to false.
597  */
598 function edit_tag_link( $link = '', $before = '', $after = '', $tag = null ) {
599         $tag = get_term($tag, 'post_tag');
600
601         if ( !current_user_can('manage_categories') )
602                 return;
603
604         if ( empty($link) )
605                 $link = __('Edit This');
606
607         $link = '<a href="' . get_edit_tag_link( $tag->term_id ) . '" title="' . __( 'Edit tag' ) . '">' . $link . '</a>';
608         echo $before . apply_filters( 'edit_tag_link', $link, $tag->term_id ) . $after;
609 }
610
611 /**
612  * Retrieve the permalink for the feed of the search results.
613  *
614  * @since 2.5.0
615  *
616  * @param string $search_query Optional. Search query.
617  * @param string $feed Optional. Feed type.
618  * @return string
619  */
620 function get_search_feed_link($search_query = '', $feed = '') {
621         if ( empty($search_query) )
622                 $search = esc_attr( urlencode(get_search_query()) );
623         else
624                 $search = esc_attr( urlencode(stripslashes($search_query)) );
625
626         if ( empty($feed) )
627                 $feed = get_default_feed();
628
629         $link = trailingslashit(get_option('home')) . "?s=$search&amp;feed=$feed";
630
631         $link = apply_filters('search_feed_link', $link);
632
633         return $link;
634 }
635
636 /**
637  * Retrieve the permalink for the comments feed of the search results.
638  *
639  * @since 2.5.0
640  *
641  * @param string $search_query Optional. Search query.
642  * @param string $feed Optional. Feed type.
643  * @return string
644  */
645 function get_search_comments_feed_link($search_query = '', $feed = '') {
646         if ( empty($search_query) )
647                 $search = esc_attr( urlencode(get_search_query()) );
648         else
649                 $search = esc_attr( urlencode(stripslashes($search_query)) );
650
651         if ( empty($feed) )
652                 $feed = get_default_feed();
653
654         $link = trailingslashit(get_option('home')) . "?s=$search&amp;feed=comments-$feed";
655
656         $link = apply_filters('search_feed_link', $link);
657
658         return $link;
659 }
660
661 /**
662  * Retrieve edit posts link for post.
663  *
664  * Can be used within the WordPress loop or outside of it. Can be used with
665  * pages, posts, attachments, and revisions.
666  *
667  * @since 2.3.0
668  *
669  * @param int $id Optional. Post ID.
670  * @param string $context Optional, default to display. How to write the '&', defaults to '&amp;'.
671  * @return string
672  */
673 function get_edit_post_link( $id = 0, $context = 'display' ) {
674         if ( !$post = &get_post( $id ) )
675                 return;
676
677         if ( 'display' == $context )
678                 $action = 'action=edit&amp;';
679         else
680                 $action = 'action=edit&';
681
682         switch ( $post->post_type ) :
683         case 'page' :
684                 if ( !current_user_can( 'edit_page', $post->ID ) )
685                         return;
686                 $file = 'page';
687                 $var  = 'post';
688                 break;
689         case 'attachment' :
690                 if ( !current_user_can( 'edit_post', $post->ID ) )
691                         return;
692                 $file = 'media';
693                 $var  = 'attachment_id';
694                 break;
695         case 'revision' :
696                 if ( !current_user_can( 'edit_post', $post->ID ) )
697                         return;
698                 $file = 'revision';
699                 $var  = 'revision';
700                 $action = '';
701                 break;
702         default :
703                 if ( !current_user_can( 'edit_post', $post->ID ) )
704                         return apply_filters( 'get_edit_post_link', '', $post->ID, $context );;
705                 $file = 'post';
706                 $var  = 'post';
707                 break;
708         endswitch;
709
710         return apply_filters( 'get_edit_post_link', admin_url("$file.php?{$action}$var=$post->ID"), $post->ID, $context );
711 }
712
713 /**
714  * Display edit post link for post.
715  *
716  * @since 1.0.0
717  *
718  * @param string $link Optional. Anchor text.
719  * @param string $before Optional. Display before edit link.
720  * @param string $after Optional. Display after edit link.
721  * @param int $id Optional. Post ID.
722  */
723 function edit_post_link( $link = null, $before = '', $after = '', $id = 0 ) {
724         if ( !$post = &get_post( $id ) )
725                 return;
726
727         if ( !$url = get_edit_post_link( $post->ID ) )
728                 return;
729
730         if ( null === $link )
731                 $link = __('Edit This');
732
733         $link = '<a class="post-edit-link" href="' . $url . '" title="' . esc_attr( __( 'Edit post' ) ) . '">' . $link . '</a>';
734         echo $before . apply_filters( 'edit_post_link', $link, $post->ID ) . $after;
735 }
736
737 /**
738  * Retrieve delete posts link for post.
739  *
740  * Can be used within the WordPress loop or outside of it. Can be used with
741  * pages, posts, attachments, and revisions.
742  *
743  * @since 2.9.0
744  *
745  * @param int $id Optional. Post ID.
746  * @param string $context Optional, default to display. How to write the '&', defaults to '&amp;'.
747  * @return string
748  */
749 function get_delete_post_link($id = 0, $context = 'display') {
750         if ( !$post = &get_post( $id ) )
751                 return;
752
753         if ( 'display' == $context )
754                 $action = 'action=trash&amp;';
755         else
756                 $action = 'action=trash&';
757
758         switch ( $post->post_type ) :
759         case 'page' :
760                 if ( !current_user_can( 'delete_page', $post->ID ) )
761                         return;
762                 $file = 'page';
763                 $var  = 'post';
764                 break;
765         case 'attachment' :
766                 if ( !current_user_can( 'delete_post', $post->ID ) )
767                         return;
768                 $file = 'media';
769                 $var  = 'attachment_id';
770                 break;
771         case 'revision' :
772                 if ( !current_user_can( 'delete_post', $post->ID ) )
773                         return;
774                 $file = 'revision';
775                 $var  = 'revision';
776                 $action = '';
777                 break;
778         default :
779                 if ( !current_user_can( 'edit_post', $post->ID ) )
780                         return apply_filters( 'get_delete_post_link', '', $post->ID, $context );;
781                 $file = 'post';
782                 $var  = 'post';
783                 break;
784         endswitch;
785
786         return apply_filters( 'get_delete_post_link', wp_nonce_url( admin_url("$file.php?{$action}$var=$post->ID"), "trash-{$file}_" . $post->ID ), $context );
787 }
788
789 /**
790  * Retrieve edit comment link.
791  *
792  * @since 2.3.0
793  *
794  * @param int $comment_id Optional. Comment ID.
795  * @return string
796  */
797 function get_edit_comment_link( $comment_id = 0 ) {
798         $comment = &get_comment( $comment_id );
799         $post = &get_post( $comment->comment_post_ID );
800
801         if ( $post->post_type == 'page' ) {
802                 if ( !current_user_can( 'edit_page', $post->ID ) )
803                         return;
804         } else {
805                 if ( !current_user_can( 'edit_post', $post->ID ) )
806                         return;
807         }
808
809         $location = admin_url('comment.php?action=editcomment&amp;c=') . $comment->comment_ID;
810         return apply_filters( 'get_edit_comment_link', $location );
811 }
812
813 /**
814  * Display or retrieve edit comment link with formatting.
815  *
816  * @since 1.0.0
817  *
818  * @param string $link Optional. Anchor text.
819  * @param string $before Optional. Display before edit link.
820  * @param string $after Optional. Display after edit link.
821  * @return string|null HTML content, if $echo is set to false.
822  */
823 function edit_comment_link( $link = null, $before = '', $after = '' ) {
824         global $comment, $post;
825
826         if ( $post->post_type == 'page' ) {
827                 if ( !current_user_can( 'edit_page', $post->ID ) )
828                         return;
829         } else {
830                 if ( !current_user_can( 'edit_post', $post->ID ) )
831                         return;
832         }
833
834         if ( null === $link )
835                 $link = __('Edit This');
836
837         $link = '<a class="comment-edit-link" href="' . get_edit_comment_link( $comment->comment_ID ) . '" title="' . __( 'Edit comment' ) . '">' . $link . '</a>';
838         echo $before . apply_filters( 'edit_comment_link', $link, $comment->comment_ID ) . $after;
839 }
840
841 /**
842  * Display edit bookmark (literally a URL external to blog) link.
843  *
844  * @since 2.7.0
845  *
846  * @param int $link Optional. Bookmark ID.
847  * @return string
848  */
849 function get_edit_bookmark_link( $link = 0 ) {
850         $link = get_bookmark( $link );
851
852         if ( !current_user_can('manage_links') )
853                 return;
854
855         $location = admin_url('link.php?action=edit&amp;link_id=') . $link->link_id;
856         return apply_filters( 'get_edit_bookmark_link', $location, $link->link_id );
857 }
858
859 /**
860  * Display edit bookmark (literally a URL external to blog) link anchor content.
861  *
862  * @since 2.7.0
863  *
864  * @param string $link Optional. Anchor text.
865  * @param string $before Optional. Display before edit link.
866  * @param string $after Optional. Display after edit link.
867  * @param int $bookmark Optional. Bookmark ID.
868  */
869 function edit_bookmark_link( $link = '', $before = '', $after = '', $bookmark = null ) {
870         $bookmark = get_bookmark($bookmark);
871
872         if ( !current_user_can('manage_links') )
873                 return;
874
875         if ( empty($link) )
876                 $link = __('Edit This');
877
878         $link = '<a href="' . get_edit_bookmark_link( $link ) . '" title="' . __( 'Edit link' ) . '">' . $link . '</a>';
879         echo $before . apply_filters( 'edit_bookmark_link', $link, $bookmark->link_id ) . $after;
880 }
881
882 // Navigation links
883
884 /**
885  * Retrieve previous post link that is adjacent to current post.
886  *
887  * @since 1.5.0
888  *
889  * @param bool $in_same_cat Optional. Whether link should be in same category.
890  * @param string $excluded_categories Optional. Excluded categories IDs.
891  * @return string
892  */
893 function get_previous_post($in_same_cat = false, $excluded_categories = '') {
894         return get_adjacent_post($in_same_cat, $excluded_categories);
895 }
896
897 /**
898  * Retrieve next post link that is adjacent to current post.
899  *
900  * @since 1.5.0
901  *
902  * @param bool $in_same_cat Optional. Whether link should be in same category.
903  * @param string $excluded_categories Optional. Excluded categories IDs.
904  * @return string
905  */
906 function get_next_post($in_same_cat = false, $excluded_categories = '') {
907         return get_adjacent_post($in_same_cat, $excluded_categories, false);
908 }
909
910 /**
911  * Retrieve adjacent post link.
912  *
913  * Can either be next or previous post link.
914  *
915  * @since 2.5.0
916  *
917  * @param bool $in_same_cat Optional. Whether link should be in same category.
918  * @param string $excluded_categories Optional. Excluded categories IDs.
919  * @param bool $previous Optional. Whether to retrieve previous post.
920  * @return string
921  */
922 function get_adjacent_post($in_same_cat = false, $excluded_categories = '', $previous = true) {
923         global $post, $wpdb;
924
925         if ( empty($post) || !is_single() || is_attachment() )
926                 return null;
927
928         $current_post_date = $post->post_date;
929
930         $join = '';
931         $posts_in_ex_cats_sql = '';
932         if ( $in_same_cat || !empty($excluded_categories) ) {
933                 $join = " INNER JOIN $wpdb->term_relationships AS tr ON p.ID = tr.object_id INNER JOIN $wpdb->term_taxonomy tt ON tr.term_taxonomy_id = tt.term_taxonomy_id";
934
935                 if ( $in_same_cat ) {
936                         $cat_array = wp_get_object_terms($post->ID, 'category', 'fields=ids');
937                         $join .= " AND tt.taxonomy = 'category' AND tt.term_id IN (" . implode(',', $cat_array) . ")";
938                 }
939
940                 $posts_in_ex_cats_sql = "AND tt.taxonomy = 'category'";
941                 if ( !empty($excluded_categories) ) {
942                         $excluded_categories = array_map('intval', explode(' and ', $excluded_categories));
943                         if ( !empty($cat_array) ) {
944                                 $excluded_categories = array_diff($excluded_categories, $cat_array);
945                                 $posts_in_ex_cats_sql = '';
946                         }
947
948                         if ( !empty($excluded_categories) ) {
949                                 $posts_in_ex_cats_sql = " AND tt.taxonomy = 'category' AND tt.term_id NOT IN (" . implode($excluded_categories, ',') . ')';
950                         }
951                 }
952         }
953
954         $adjacent = $previous ? 'previous' : 'next';
955         $op = $previous ? '<' : '>';
956         $order = $previous ? 'DESC' : 'ASC';
957
958         $join  = apply_filters( "get_{$adjacent}_post_join", $join, $in_same_cat, $excluded_categories );
959         $where = apply_filters( "get_{$adjacent}_post_where", $wpdb->prepare("WHERE p.post_date $op %s AND p.post_type = %s AND p.post_status = 'publish' $posts_in_ex_cats_sql", $current_post_date, $post->post_type), $in_same_cat, $excluded_categories );
960         $sort  = apply_filters( "get_{$adjacent}_post_sort", "ORDER BY p.post_date $order LIMIT 1" );
961
962         $query = "SELECT p.* FROM $wpdb->posts AS p $join $where $sort";
963         $query_key = 'adjacent_post_' . md5($query);
964         $result = wp_cache_get($query_key, 'counts');
965         if ( false !== $result )
966                 return $result;
967
968         $result = $wpdb->get_row("SELECT p.* FROM $wpdb->posts AS p $join $where $sort");
969         if ( null === $result )
970                 $result = '';
971
972         wp_cache_set($query_key, $result, 'counts');
973         return $result;
974 }
975
976 /**
977  * Get adjacent post relational link.
978  *
979  * Can either be next or previous post relational link.
980  *
981  * @since 2.8.0
982  *
983  * @param string $title Optional. Link title format.
984  * @param bool $in_same_cat Optional. Whether link should be in same category.
985  * @param string $excluded_categories Optional. Excluded categories IDs.
986  * @param bool $previous Optional, default is true. Whether display link to previous post.
987  * @return string
988  */
989 function get_adjacent_post_rel_link($title = '%title', $in_same_cat = false, $excluded_categories = '', $previous = true) {
990         if ( $previous && is_attachment() )
991                 $post = & get_post($GLOBALS['post']->post_parent);
992         else
993                 $post = get_adjacent_post($in_same_cat,$excluded_categories,$previous);
994
995         if ( empty($post) )
996                 return;
997
998         if ( empty($post->post_title) )
999                 $post->post_title = $previous ? __('Previous Post') : __('Next Post');
1000
1001         $date = mysql2date(get_option('date_format'), $post->post_date);
1002
1003         $title = str_replace('%title', $post->post_title, $title);
1004         $title = str_replace('%date', $date, $title);
1005         $title = apply_filters('the_title', $title, $post);
1006
1007         $link = $previous ? "<link rel='prev' title='" : "<link rel='next' title='";
1008         $link .= esc_attr( $title );
1009         $link .= "' href='" . get_permalink($post) . "' />\n";
1010
1011         $adjacent = $previous ? 'previous' : 'next';
1012         return apply_filters( "{$adjacent}_post_rel_link", $link );
1013 }
1014
1015 /**
1016  * Display relational links for the posts adjacent to the current post.
1017  *
1018  * @since 2.8.0
1019  *
1020  * @param string $title Optional. Link title format.
1021  * @param bool $in_same_cat Optional. Whether link should be in same category.
1022  * @param string $excluded_categories Optional. Excluded categories IDs.
1023  */
1024 function adjacent_posts_rel_link($title = '%title', $in_same_cat = false, $excluded_categories = '') {
1025         echo get_adjacent_post_rel_link($title, $in_same_cat, $excluded_categories = '', true);
1026         echo get_adjacent_post_rel_link($title, $in_same_cat, $excluded_categories = '', false);
1027 }
1028
1029 /**
1030  * Display relational link for the next post adjacent to the current post.
1031  *
1032  * @since 2.8.0
1033  *
1034  * @param string $title Optional. Link title format.
1035  * @param bool $in_same_cat Optional. Whether link should be in same category.
1036  * @param string $excluded_categories Optional. Excluded categories IDs.
1037  */
1038 function next_post_rel_link($title = '%title', $in_same_cat = false, $excluded_categories = '') {
1039         echo get_adjacent_post_rel_link($title, $in_same_cat, $excluded_categories = '', false);
1040 }
1041
1042 /**
1043  * Display relational link for the previous post adjacent to the current post.
1044  *
1045  * @since 2.8.0
1046  *
1047  * @param string $title Optional. Link title format.
1048  * @param bool $in_same_cat Optional. Whether link should be in same category.
1049  * @param string $excluded_categories Optional. Excluded categories IDs.
1050  */
1051 function prev_post_rel_link($title = '%title', $in_same_cat = false, $excluded_categories = '') {
1052         echo get_adjacent_post_rel_link($title, $in_same_cat, $excluded_categories = '', true);
1053 }
1054
1055 /**
1056  * Retrieve boundary post.
1057  *
1058  * Boundary being either the first or last post by publish date within the contraitns specified
1059  * by in same category or excluded categories.
1060  *
1061  * @since 2.8.0
1062  *
1063  * @param bool $in_same_cat Optional. Whether returned post should be in same category.
1064  * @param string $excluded_categories Optional. Excluded categories IDs.
1065  * @param bool $previous Optional. Whether to retrieve first post.
1066  * @return object
1067  */
1068 function get_boundary_post($in_same_cat = false, $excluded_categories = '', $start = true) {
1069         global $post, $wpdb;
1070
1071         if ( empty($post) || !is_single() || is_attachment() )
1072                 return null;
1073
1074         $cat_array = array();
1075         $excluded_categories = array();
1076         if ( !empty($in_same_cat) || !empty($excluded_categories) ) {
1077                 if ( !empty($in_same_cat) ) {
1078                         $cat_array = wp_get_object_terms($post->ID, 'category', 'fields=ids');
1079                 }
1080
1081                 if ( !empty($excluded_categories) ) {
1082                         $excluded_categories = array_map('intval', explode(',', $excluded_categories));
1083
1084                         if ( !empty($cat_array) )
1085                                 $excluded_categories = array_diff($excluded_categories, $cat_array);
1086
1087                         $inverse_cats = array();
1088                         foreach ( $excluded_categories as $excluded_category)
1089                                 $inverse_cats[] = $excluded_category * -1;
1090                         $excluded_categories = $inverse_cats;
1091                 }
1092         }
1093
1094         $categories = implode(',', array_merge($cat_array, $excluded_categories) );
1095
1096         $order = $start ? 'ASC' : 'DESC';
1097
1098         return get_posts( array('numberposts' => 1, 'order' => $order, 'orderby' => 'ID', 'category' => $categories) );
1099 }
1100
1101 /**
1102  * Get boundary post relational link.
1103  *
1104  * Can either be start or end post relational link.
1105  *
1106  * @since 2.8.0
1107  *
1108  * @param string $title Optional. Link title format.
1109  * @param bool $in_same_cat Optional. Whether link should be in same category.
1110  * @param string $excluded_categories Optional. Excluded categories IDs.
1111  * @param bool $start Optional, default is true. Whether display link to first post.
1112  * @return string
1113  */
1114 function get_boundary_post_rel_link($title = '%title', $in_same_cat = false, $excluded_categories = '', $start = true) {
1115         $posts = get_boundary_post($in_same_cat,$excluded_categories,$start);
1116         // Even though we limited get_posts to return only 1 item it still returns an array of objects.
1117         $post = $posts[0];
1118
1119         if ( empty($post) )
1120                          return;
1121
1122                 if ( empty($post->post_title) )
1123                                 $post->post_title = $start ? __('First Post') : __('Last Post');
1124
1125         $date = mysql2date(get_option('date_format'), $post->post_date);
1126
1127         $title = str_replace('%title', $post->post_title, $title);
1128         $title = str_replace('%date', $date, $title);
1129         $title = apply_filters('the_title', $title, $post);
1130
1131         $link = $start ? "<link rel='start' title='" : "<link rel='end' title='";
1132         $link .= esc_attr($title);
1133         $link .= "' href='" . get_permalink($post) . "' />\n";
1134
1135         $boundary = $start ? 'start' : 'end';
1136         return apply_filters( "{$boundary}_post_rel_link", $link );
1137 }
1138
1139 /**
1140  * Display relational link for the first post.
1141  *
1142  * @since 2.8.0
1143  *
1144  * @param string $title Optional. Link title format.
1145  * @param bool $in_same_cat Optional. Whether link should be in same category.
1146  * @param string $excluded_categories Optional. Excluded categories IDs.
1147  */
1148 function start_post_rel_link($title = '%title', $in_same_cat = false, $excluded_categories = '') {
1149         echo get_boundary_post_rel_link($title, $in_same_cat, $excluded_categories, true);
1150 }
1151
1152 /**
1153  * Get site index relational link.
1154  *
1155  * @since 2.8.0
1156  *
1157  * @return string
1158  */
1159 function get_index_rel_link() {
1160         $link = "<link rel='index' title='" . esc_attr(get_bloginfo('name')) . "' href='" . get_bloginfo('siteurl') . "' />\n";
1161         return apply_filters( "index_rel_link", $link );
1162 }
1163
1164 /**
1165  * Display relational link for the site index.
1166  *
1167  * @since 2.8.0
1168  */
1169 function index_rel_link() {
1170         echo get_index_rel_link();
1171 }
1172
1173 /**
1174  * Get parent post relational link.
1175  *
1176  * @since 2.8.0
1177  *
1178  * @param string $title Optional. Link title format.
1179  * @return string
1180  */
1181 function get_parent_post_rel_link($title = '%title') {
1182         if ( ! empty( $GLOBALS['post'] ) && ! empty( $GLOBALS['post']->post_parent ) )
1183                 $post = & get_post($GLOBALS['post']->post_parent);
1184
1185         if ( empty($post) )
1186                 return;
1187
1188         $date = mysql2date(get_option('date_format'), $post->post_date);
1189
1190         $title = str_replace('%title', $post->post_title, $title);
1191         $title = str_replace('%date', $date, $title);
1192         $title = apply_filters('the_title', $title, $post);
1193
1194         $link = "<link rel='up' title='";
1195         $link .= esc_attr( $title );
1196         $link .= "' href='" . get_permalink($post) . "' />\n";
1197
1198         return apply_filters( "parent_post_rel_link", $link );
1199 }
1200
1201 /**
1202  * Display relational link for parent item
1203  *
1204  * @since 2.8.0
1205  */
1206 function parent_post_rel_link($title = '%title') {
1207         echo get_parent_post_rel_link($title);
1208 }
1209
1210 /**
1211  * Display previous post link that is adjacent to the current post.
1212  *
1213  * @since 1.5.0
1214  *
1215  * @param string $format Optional. Link anchor format.
1216  * @param string $link Optional. Link permalink format.
1217  * @param bool $in_same_cat Optional. Whether link should be in same category.
1218  * @param string $excluded_categories Optional. Excluded categories IDs.
1219  */
1220 function previous_post_link($format='&laquo; %link', $link='%title', $in_same_cat = false, $excluded_categories = '') {
1221         adjacent_post_link($format, $link, $in_same_cat, $excluded_categories, true);
1222 }
1223
1224 /**
1225  * Display next post link that is adjacent to the current post.
1226  *
1227  * @since 1.5.0
1228  *
1229  * @param string $format Optional. Link anchor format.
1230  * @param string $link Optional. Link permalink format.
1231  * @param bool $in_same_cat Optional. Whether link should be in same category.
1232  * @param string $excluded_categories Optional. Excluded categories IDs.
1233  */
1234 function next_post_link($format='%link &raquo;', $link='%title', $in_same_cat = false, $excluded_categories = '') {
1235         adjacent_post_link($format, $link, $in_same_cat, $excluded_categories, false);
1236 }
1237
1238 /**
1239  * Display adjacent post link.
1240  *
1241  * Can be either next post link or previous.
1242  *
1243  * @since 2.5.0
1244  *
1245  * @param string $format Link anchor format.
1246  * @param string $link Link permalink format.
1247  * @param bool $in_same_cat Optional. Whether link should be in same category.
1248  * @param string $excluded_categories Optional. Excluded categories IDs.
1249  * @param bool $previous Optional, default is true. Whether display link to previous post.
1250  */
1251 function adjacent_post_link($format, $link, $in_same_cat = false, $excluded_categories = '', $previous = true) {
1252         if ( $previous && is_attachment() )
1253                 $post = & get_post($GLOBALS['post']->post_parent);
1254         else
1255                 $post = get_adjacent_post($in_same_cat, $excluded_categories, $previous);
1256
1257         if ( !$post )
1258                 return;
1259
1260         $title = $post->post_title;
1261
1262         if ( empty($post->post_title) )
1263                 $title = $previous ? __('Previous Post') : __('Next Post');
1264
1265         $title = apply_filters('the_title', $title, $post);
1266         $date = mysql2date(get_option('date_format'), $post->post_date);
1267         $rel = $previous ? 'prev' : 'next';
1268
1269         $string = '<a href="'.get_permalink($post).'" rel="'.$rel.'">';
1270         $link = str_replace('%title', $title, $link);
1271         $link = str_replace('%date', $date, $link);
1272         $link = $string . $link . '</a>';
1273
1274         $format = str_replace('%link', $link, $format);
1275
1276         $adjacent = $previous ? 'previous' : 'next';
1277         echo apply_filters( "{$adjacent}_post_link", $format, $link );
1278 }
1279
1280 /**
1281  * Retrieve get links for page numbers.
1282  *
1283  * @since 1.5.0
1284  *
1285  * @param int $pagenum Optional. Page ID.
1286  * @return string
1287  */
1288 function get_pagenum_link($pagenum = 1) {
1289         global $wp_rewrite;
1290
1291         $pagenum = (int) $pagenum;
1292
1293         $request = remove_query_arg( 'paged' );
1294
1295         $home_root = parse_url(get_option('home'));
1296         $home_root = ( isset($home_root['path']) ) ? $home_root['path'] : '';
1297         $home_root = preg_quote( trailingslashit( $home_root ), '|' );
1298
1299         $request = preg_replace('|^'. $home_root . '|', '', $request);
1300         $request = preg_replace('|^/+|', '', $request);
1301
1302         if ( !$wp_rewrite->using_permalinks() || is_admin() ) {
1303                 $base = trailingslashit( get_bloginfo( 'home' ) );
1304
1305                 if ( $pagenum > 1 ) {
1306                         $result = add_query_arg( 'paged', $pagenum, $base . $request );
1307                 } else {
1308                         $result = $base . $request;
1309                 }
1310         } else {
1311                 $qs_regex = '|\?.*?$|';
1312                 preg_match( $qs_regex, $request, $qs_match );
1313
1314                 if ( !empty( $qs_match[0] ) ) {
1315                         $query_string = $qs_match[0];
1316                         $request = preg_replace( $qs_regex, '', $request );
1317                 } else {
1318                         $query_string = '';
1319                 }
1320
1321                 $request = preg_replace( '|page/\d+/?$|', '', $request);
1322                 $request = preg_replace( '|^index\.php|', '', $request);
1323                 $request = ltrim($request, '/');
1324
1325                 $base = trailingslashit( get_bloginfo( 'url' ) );
1326
1327                 if ( $wp_rewrite->using_index_permalinks() && ( $pagenum > 1 || '' != $request ) )
1328                         $base .= 'index.php/';
1329
1330                 if ( $pagenum > 1 ) {
1331                         $request = ( ( !empty( $request ) ) ? trailingslashit( $request ) : $request ) . user_trailingslashit( 'page/' . $pagenum, 'paged' );
1332                 }
1333
1334                 $result = $base . $request . $query_string;
1335         }
1336
1337         $result = apply_filters('get_pagenum_link', $result);
1338
1339         return $result;
1340 }
1341
1342 /**
1343  * Retrieve next posts pages link.
1344  *
1345  * Backported from 2.1.3 to 2.0.10.
1346  *
1347  * @since 2.0.10
1348  *
1349  * @param int $max_page Optional. Max pages.
1350  * @return string
1351  */
1352 function get_next_posts_page_link($max_page = 0) {
1353         global $paged;
1354
1355         if ( !is_single() ) {
1356                 if ( !$paged )
1357                         $paged = 1;
1358                 $nextpage = intval($paged) + 1;
1359                 if ( !$max_page || $max_page >= $nextpage )
1360                         return get_pagenum_link($nextpage);
1361         }
1362 }
1363
1364 /**
1365  * Display or return the next posts pages link.
1366  *
1367  * @since 0.71
1368  *
1369  * @param int $max_page Optional. Max pages.
1370  * @param boolean $echo Optional. Echo or return;
1371  */
1372 function next_posts( $max_page = 0, $echo = true ) {
1373         $output = esc_url( get_next_posts_page_link( $max_page ) );
1374
1375         if ( $echo )
1376                 echo $output;
1377         else
1378                 return $output;
1379 }
1380
1381 /**
1382  * Return the next posts pages link.
1383  *
1384  * @since 2.7.0
1385  *
1386  * @param string $label Content for link text.
1387  * @param int $max_page Optional. Max pages.
1388  * @return string|null
1389  */
1390 function get_next_posts_link( $label = 'Next Page &raquo;', $max_page = 0 ) {
1391         global $paged, $wp_query;
1392
1393         if ( !$max_page ) {
1394                 $max_page = $wp_query->max_num_pages;
1395         }
1396
1397         if ( !$paged )
1398                 $paged = 1;
1399
1400         $nextpage = intval($paged) + 1;
1401
1402         if ( !is_single() && ( empty($paged) || $nextpage <= $max_page) ) {
1403                 $attr = apply_filters( 'next_posts_link_attributes', '' );
1404                 return '<a href="' . next_posts( $max_page, false ) . "\" $attr>". preg_replace('/&([^#])(?![a-z]{1,8};)/', '&#038;$1', $label) .'</a>';
1405         }
1406 }
1407
1408 /**
1409  * Display the next posts pages link.
1410  *
1411  * @since 0.71
1412  * @uses get_next_posts_link()
1413  *
1414  * @param string $label Content for link text.
1415  * @param int $max_page Optional. Max pages.
1416  */
1417 function next_posts_link( $label = 'Next Page &raquo;', $max_page = 0 ) {
1418         echo get_next_posts_link( $label, $max_page );
1419 }
1420
1421 /**
1422  * Retrieve previous post pages link.
1423  *
1424  * Will only return string, if not on a single page or post.
1425  *
1426  * Backported to 2.0.10 from 2.1.3.
1427  *
1428  * @since 2.0.10
1429  *
1430  * @return string|null
1431  */
1432 function get_previous_posts_page_link() {
1433         global $paged;
1434
1435         if ( !is_single() ) {
1436                 $nextpage = intval($paged) - 1;
1437                 if ( $nextpage < 1 )
1438                         $nextpage = 1;
1439                 return get_pagenum_link($nextpage);
1440         }
1441 }
1442
1443 /**
1444  * Display or return the previous posts pages link.
1445  *
1446  * @since 0.71
1447  *
1448  * @param boolean $echo Optional. Echo or return;
1449  */
1450 function previous_posts( $echo = true ) {
1451         $output = esc_url( get_previous_posts_page_link() );
1452
1453         if ( $echo )
1454                 echo $output;
1455         else
1456                 return $output;
1457 }
1458
1459 /**
1460  * Return the previous posts pages link.
1461  *
1462  * @since 2.7.0
1463  *
1464  * @param string $label Optional. Previous page link text.
1465  * @return string|null
1466  */
1467 function get_previous_posts_link( $label = '&laquo; Previous Page' ) {
1468         global $paged;
1469
1470         if ( !is_single() && $paged > 1 ) {
1471                 $attr = apply_filters( 'previous_posts_link_attributes', '' );
1472                 return '<a href="' . previous_posts( false ) . "\" $attr>". preg_replace( '/&([^#])(?![a-z]{1,8};)/', '&#038;$1', $label ) .'</a>';
1473         }
1474 }
1475
1476 /**
1477  * Display the previous posts page link.
1478  *
1479  * @since 0.71
1480  * @uses get_previous_posts_link()
1481  *
1482  * @param string $label Optional. Previous page link text.
1483  */
1484 function previous_posts_link( $label = '&laquo; Previous Page' ) {
1485         echo get_previous_posts_link( $label );
1486 }
1487
1488 /**
1489  * Return post pages link navigation for previous and next pages.
1490  *
1491  * @since 2.8
1492  *
1493  * @param string|array $args Optional args.
1494  * @return string The posts link navigation.
1495  */
1496 function get_posts_nav_link( $args = array() ) {
1497         global $wp_query;
1498
1499         $return = '';
1500
1501         if ( !is_singular() ) {
1502                 $defaults = array(
1503                         'sep' => ' &#8212; ',
1504                         'prelabel' => __('&laquo; Previous Page'),
1505                         'nxtlabel' => __('Next Page &raquo;'),
1506                 );
1507                 $args = wp_parse_args( $args, $defaults );
1508
1509                 $max_num_pages = $wp_query->max_num_pages;
1510                 $paged = get_query_var('paged');
1511
1512                 //only have sep if there's both prev and next results
1513                 if ($paged < 2 || $paged >= $max_num_pages) {
1514                         $args['sep'] = '';
1515                 }
1516
1517                 if ( $max_num_pages > 1 ) {
1518                         $return = get_previous_posts_link($args['prelabel']);
1519                         $return .= preg_replace('/&([^#])(?![a-z]{1,8};)/', '&#038;$1', $args['sep']);
1520                         $return .= get_next_posts_link($args['nxtlabel']);
1521                 }
1522         }
1523         return $return;
1524
1525 }
1526
1527 /**
1528  * Display post pages link navigation for previous and next pages.
1529  *
1530  * @since 0.71
1531  *
1532  * @param string $sep Optional. Separator for posts navigation links.
1533  * @param string $prelabel Optional. Label for previous pages.
1534  * @param string $nxtlabel Optional Label for next pages.
1535  */
1536 function posts_nav_link( $sep = '', $prelabel = '', $nxtlabel = '' ) {
1537         $args = array_filter( compact('sep', 'prelabel', 'nxtlabel') );
1538         echo get_posts_nav_link($args);
1539 }
1540
1541 /**
1542  * Retrieve page numbers links.
1543  *
1544  * @since 2.7.0
1545  *
1546  * @param int $pagenum Optional. Page number.
1547  * @return string
1548  */
1549 function get_comments_pagenum_link( $pagenum = 1, $max_page = 0 ) {
1550         global $post, $wp_rewrite;
1551
1552         $pagenum = (int) $pagenum;
1553
1554         $result = get_permalink( $post->ID );
1555
1556         if ( 'newest' == get_option('default_comments_page') ) {
1557                 if ( $pagenum != $max_page ) {
1558                         if ( $wp_rewrite->using_permalinks() )
1559                                 $result = user_trailingslashit( trailingslashit($result) . 'comment-page-' . $pagenum, 'commentpaged');
1560                         else
1561                                 $result = add_query_arg( 'cpage', $pagenum, $result );
1562                 }
1563         } elseif ( $pagenum > 1 ) {
1564                 if ( $wp_rewrite->using_permalinks() )
1565                         $result = user_trailingslashit( trailingslashit($result) . 'comment-page-' . $pagenum, 'commentpaged');
1566                 else
1567                         $result = add_query_arg( 'cpage', $pagenum, $result );
1568         }
1569
1570         $result .= '#comments';
1571
1572         $result = apply_filters('get_comments_pagenum_link', $result);
1573
1574         return $result;
1575 }
1576
1577 /**
1578  * Return the link to next comments pages.
1579  *
1580  * @since 2.7.1
1581  *
1582  * @param string $label Optional. Label for link text.
1583  * @param int $max_page Optional. Max page.
1584  * @return string|null
1585  */
1586 function get_next_comments_link( $label = '', $max_page = 0 ) {
1587         global $wp_query;
1588
1589         if ( !is_singular() || !get_option('page_comments') )
1590                 return;
1591
1592         $page = get_query_var('cpage');
1593
1594         $nextpage = intval($page) + 1;
1595
1596         if ( empty($max_page) )
1597                 $max_page = $wp_query->max_num_comment_pages;
1598
1599         if ( empty($max_page) )
1600                 $max_page = get_comment_pages_count();
1601
1602         if ( $nextpage > $max_page )
1603                 return;
1604
1605         if ( empty($label) )
1606                 $label = __('Newer Comments &raquo;');
1607
1608         return '<a href="' . esc_url( get_comments_pagenum_link( $nextpage, $max_page ) ) . '" ' . apply_filters( 'next_comments_link_attributes', '' ) . '>'. preg_replace('/&([^#])(?![a-z]{1,8};)/', '&#038;$1', $label) .'</a>';
1609 }
1610
1611 /**
1612  * Display the link to next comments pages.
1613  *
1614  * @since 2.7.0
1615  *
1616  * @param string $label Optional. Label for link text.
1617  * @param int $max_page Optional. Max page.
1618  */
1619 function next_comments_link( $label = '', $max_page = 0 ) {
1620         echo get_next_comments_link( $label, $max_page );
1621 }
1622
1623 /**
1624  * Return the previous comments page link.
1625  *
1626  * @since 2.7.1
1627  *
1628  * @param string $label Optional. Label for comments link text.
1629  * @return string|null
1630  */
1631 function get_previous_comments_link( $label = '' ) {
1632         if ( !is_singular() || !get_option('page_comments') )
1633                 return;
1634
1635         $page = get_query_var('cpage');
1636
1637         if ( intval($page) <= 1 )
1638                 return;
1639
1640         $prevpage = intval($page) - 1;
1641
1642         if ( empty($label) )
1643                 $label = __('&laquo; Older Comments');
1644
1645         return '<a href="' . esc_url( get_comments_pagenum_link( $prevpage ) ) . '" ' . apply_filters( 'previous_comments_link_attributes', '' ) . '>' . preg_replace('/&([^#])(?![a-z]{1,8};)/', '&#038;$1', $label) .'</a>';
1646 }
1647
1648 /**
1649  * Display the previous comments page link.
1650  *
1651  * @since 2.7.0
1652  *
1653  * @param string $label Optional. Label for comments link text.
1654  */
1655 function previous_comments_link( $label = '' ) {
1656         echo get_previous_comments_link( $label );
1657 }
1658
1659 /**
1660  * Create pagination links for the comments on the current post.
1661  *
1662  * @see paginate_links()
1663  * @since 2.7.0
1664  *
1665  * @param string|array $args Optional args. See paginate_links.
1666  * @return string Markup for pagination links.
1667 */
1668 function paginate_comments_links($args = array()) {
1669         global $wp_query, $wp_rewrite;
1670
1671         if ( !is_singular() || !get_option('page_comments') )
1672                 return;
1673
1674         $page = get_query_var('cpage');
1675         if ( !$page )
1676                 $page = 1;
1677         $max_page = get_comment_pages_count();
1678         $defaults = array(
1679                 'base' => add_query_arg( 'cpage', '%#%' ),
1680                 'format' => '',
1681                 'total' => $max_page,
1682                 'current' => $page,
1683                 'echo' => true,
1684                 'add_fragment' => '#comments'
1685         );
1686         if ( $wp_rewrite->using_permalinks() )
1687                 $defaults['base'] = user_trailingslashit(trailingslashit(get_permalink()) . 'comment-page-%#%', 'commentpaged');
1688
1689         $args = wp_parse_args( $args, $defaults );
1690         $page_links = paginate_links( $args );
1691
1692         if ( $args['echo'] )
1693                 echo $page_links;
1694         else
1695                 return $page_links;
1696 }
1697
1698 /**
1699  * Retrieve shortcut link.
1700  *
1701  * Use this in 'a' element 'href' attribute.
1702  *
1703  * @since 2.6.0
1704  *
1705  * @return string
1706  */
1707 function get_shortcut_link() {
1708         $link = "javascript:
1709                         var d=document,
1710                         w=window,
1711                         e=w.getSelection,
1712                         k=d.getSelection,
1713                         x=d.selection,
1714                         s=(e?e():(k)?k():(x?x.createRange().text:0)),
1715                         f='" . admin_url('press-this.php') . "',
1716                         l=d.location,
1717                         e=encodeURIComponent,
1718                         u=f+'?u='+e(l.href)+'&t='+e(d.title)+'&s='+e(s)+'&v=4';
1719                         a=function(){if(!w.open(u,'t','toolbar=0,resizable=1,scrollbars=1,status=1,width=720,height=570'))l.href=u;};
1720                         if (/Firefox/.test(navigator.userAgent)) setTimeout(a, 0); else a();
1721                         void(0)";
1722
1723         $link = str_replace(array("\r", "\n", "\t"),  '', $link);
1724
1725         return apply_filters('shortcut_link', $link);
1726 }
1727
1728 /**
1729  * Retrieve the site url.
1730  *
1731  * Returns the 'site_url' option with the appropriate protocol,  'https' if
1732  * is_ssl() and 'http' otherwise. If $scheme is 'http' or 'https', is_ssl() is
1733  * overridden.
1734  *
1735  * @package WordPress
1736  * @since 2.6.0
1737  *
1738  * @param string $path Optional. Path relative to the site url.
1739  * @param string $scheme Optional. Scheme to give the site url context. Currently 'http','https', 'login', 'login_post', or 'admin'.
1740  * @return string Site url link with optional path appended.
1741 */
1742 function site_url($path = '', $scheme = null) {
1743         // should the list of allowed schemes be maintained elsewhere?
1744         $orig_scheme = $scheme;
1745         if ( !in_array($scheme, array('http', 'https')) ) {
1746                 if ( ( 'login_post' == $scheme || 'rpc' == $scheme ) && ( force_ssl_login() || force_ssl_admin() ) )
1747                         $scheme = 'https';
1748                 elseif ( ('login' == $scheme) && ( force_ssl_admin() ) )
1749                         $scheme = 'https';
1750                 elseif ( ('admin' == $scheme) && force_ssl_admin() )
1751                         $scheme = 'https';
1752                 else
1753                         $scheme = ( is_ssl() ? 'https' : 'http' );
1754         }
1755
1756         $url = str_replace( 'http://', "{$scheme}://", get_option('siteurl') );
1757
1758         if ( !empty($path) && is_string($path) && strpos($path, '..') === false )
1759                 $url .= '/' . ltrim($path, '/');
1760
1761         return apply_filters('site_url', $url, $path, $orig_scheme);
1762 }
1763
1764 /**
1765  * Retrieve the url to the admin area.
1766  *
1767  * @package WordPress
1768  * @since 2.6.0
1769  *
1770  * @param string $path Optional path relative to the admin url
1771  * @return string Admin url link with optional path appended
1772 */
1773 function admin_url($path = '') {
1774         $url = site_url('wp-admin/', 'admin');
1775
1776         if ( !empty($path) && is_string($path) && strpos($path, '..') === false )
1777                 $url .= ltrim($path, '/');
1778
1779         return apply_filters('admin_url', $url, $path);
1780 }
1781
1782 /**
1783  * Retrieve the url to the includes directory.
1784  *
1785  * @package WordPress
1786  * @since 2.6.0
1787  *
1788  * @param string $path Optional. Path relative to the includes url.
1789  * @return string Includes url link with optional path appended.
1790 */
1791 function includes_url($path = '') {
1792         $url = site_url() . '/' . WPINC . '/';
1793
1794         if ( !empty($path) && is_string($path) && strpos($path, '..') === false )
1795                 $url .= ltrim($path, '/');
1796
1797         return apply_filters('includes_url', $url, $path);
1798 }
1799
1800 /**
1801  * Retrieve the url to the content directory.
1802  *
1803  * @package WordPress
1804  * @since 2.6.0
1805  *
1806  * @param string $path Optional. Path relative to the content url.
1807  * @return string Content url link with optional path appended.
1808 */
1809 function content_url($path = '') {
1810         $scheme = ( is_ssl() ? 'https' : 'http' );
1811         $url = WP_CONTENT_URL;
1812         if ( 0 === strpos($url, 'http') ) {
1813                 if ( is_ssl() )
1814                         $url = str_replace( 'http://', "{$scheme}://", $url );
1815         }
1816
1817         if ( !empty($path) && is_string($path) && strpos($path, '..') === false )
1818                 $url .= '/' . ltrim($path, '/');
1819
1820         return apply_filters('content_url', $url, $path);
1821 }
1822
1823 /**
1824  * Retrieve the url to the plugins directory or to a specific file within that directory.
1825  * You can hardcode the plugin slug in $path or pass __FILE__ as a second argument to get the correct folder name.
1826  *
1827  * @package WordPress
1828  * @since 2.6.0
1829  *
1830  * @param string $path Optional. Path relative to the plugins url.
1831  * @param string $plugin Optional. The plugin file that you want to be relative to - i.e. pass in __FILE__
1832  * @return string Plugins url link with optional path appended.
1833 */
1834 function plugins_url($path = '', $plugin = '') {
1835         $scheme = ( is_ssl() ? 'https' : 'http' );
1836
1837         if ( $plugin !== '' && preg_match('#^' . preg_quote(WPMU_PLUGIN_DIR . DIRECTORY_SEPARATOR, '#') . '#', $plugin) ) {
1838                 $url = WPMU_PLUGIN_URL;
1839         } else {
1840                 $url = WP_PLUGIN_URL;
1841         }
1842
1843         if ( 0 === strpos($url, 'http') ) {
1844                 if ( is_ssl() )
1845                         $url = str_replace( 'http://', "{$scheme}://", $url );
1846         }
1847
1848         if ( !empty($plugin) && is_string($plugin) ) {
1849                 $folder = dirname(plugin_basename($plugin));
1850                 if ('.' != $folder)
1851                         $url .= '/' . ltrim($folder, '/');
1852         }
1853
1854         if ( !empty($path) && is_string($path) && strpos($path, '..') === false )
1855                 $url .= '/' . ltrim($path, '/');
1856
1857         return apply_filters('plugins_url', $url, $path, $plugin);
1858 }
1859
1860 /**
1861  * Output rel=canonical for singular queries
1862  *
1863  * @package WordPress
1864  * @since 2.9.0
1865 */
1866 function rel_canonical() {
1867         if ( !is_singular() )
1868                 return;
1869
1870         global $wp_the_query;
1871         if ( !$id = $wp_the_query->get_queried_object_id() )
1872                 return;
1873
1874         $link = get_permalink( $id );
1875         echo "<link rel='canonical' href='$link' />\n";
1876 }
1877
1878 ?>