]> scripts.mit.edu Git - autoinstalls/wordpress.git/blob - wp-includes/category-template.php
Wordpress 3.0.2-scripts
[autoinstalls/wordpress.git] / wp-includes / category-template.php
1 <?php
2 /**
3  * Category Template Tags and API.
4  *
5  * @package WordPress
6  * @subpackage Template
7  */
8
9 /**
10  * Retrieve category link URL.
11  *
12  * @since 1.0.0
13  * @uses apply_filters() Calls 'category_link' filter on category link and category ID.
14  *
15  * @param int $category_id Category ID.
16  * @return string
17  */
18 function get_category_link( $category_id ) {
19         global $wp_rewrite;
20         $catlink = $wp_rewrite->get_category_permastruct();
21
22         if ( empty( $catlink ) ) {
23                 $catlink = home_url('?cat=' . $category_id);
24         } else {
25                 $category = &get_category( $category_id );
26                 if ( is_wp_error( $category ) )
27                         return $category;
28                 $category_nicename = $category->slug;
29
30                 if ( $category->parent == $category_id ) // recursive recursion
31                         $category->parent = 0;
32                 elseif ($category->parent != 0 )
33                         $category_nicename = get_category_parents( $category->parent, false, '/', true ) . $category_nicename;
34
35                 $catlink = str_replace( '%category%', $category_nicename, $catlink );
36                 $catlink = home_url( user_trailingslashit( $catlink, 'category' ) );
37         }
38         return apply_filters( 'category_link', $catlink, $category_id );
39 }
40
41 /**
42  * Retrieve category parents with separator.
43  *
44  * @since 1.2.0
45  *
46  * @param int $id Category ID.
47  * @param bool $link Optional, default is false. Whether to format with link.
48  * @param string $separator Optional, default is '/'. How to separate categories.
49  * @param bool $nicename Optional, default is false. Whether to use nice name for display.
50  * @param array $visited Optional. Already linked to categories to prevent duplicates.
51  * @return string
52  */
53 function get_category_parents( $id, $link = false, $separator = '/', $nicename = false, $visited = array() ) {
54         $chain = '';
55         $parent = &get_category( $id );
56         if ( is_wp_error( $parent ) )
57                 return $parent;
58
59         if ( $nicename )
60                 $name = $parent->slug;
61         else
62                 $name = $parent->cat_name;
63
64         if ( $parent->parent && ( $parent->parent != $parent->term_id ) && !in_array( $parent->parent, $visited ) ) {
65                 $visited[] = $parent->parent;
66                 $chain .= get_category_parents( $parent->parent, $link, $separator, $nicename, $visited );
67         }
68
69         if ( $link )
70                 $chain .= '<a href="' . get_category_link( $parent->term_id ) . '" title="' . esc_attr( sprintf( __( "View all posts in %s" ), $parent->cat_name ) ) . '">'.$name.'</a>' . $separator;
71         else
72                 $chain .= $name.$separator;
73         return $chain;
74 }
75
76 /**
77  * Retrieve post categories.
78  *
79  * @since 0.71
80  * @uses $post
81  *
82  * @param int $id Optional, default to current post ID. The post ID.
83  * @return array
84  */
85 function get_the_category( $id = false ) {
86         global $post;
87
88         $id = (int) $id;
89         if ( !$id )
90                 $id = (int) $post->ID;
91
92         $categories = get_object_term_cache( $id, 'category' );
93         if ( false === $categories ) {
94                 $categories = wp_get_object_terms( $id, 'category' );
95                 wp_cache_add($id, $categories, 'category_relationships');
96         }
97
98         if ( !empty( $categories ) )
99                 usort( $categories, '_usort_terms_by_name' );
100         else
101                 $categories = array();
102
103         foreach ( (array) array_keys( $categories ) as $key ) {
104                 _make_cat_compat( $categories[$key] );
105         }
106
107         return $categories;
108 }
109
110 /**
111  * Sort categories by name.
112  *
113  * Used by usort() as a callback, should not be used directly. Can actually be
114  * used to sort any term object.
115  *
116  * @since 2.3.0
117  * @access private
118  *
119  * @param object $a
120  * @param object $b
121  * @return int
122  */
123 function _usort_terms_by_name( $a, $b ) {
124         return strcmp( $a->name, $b->name );
125 }
126
127 /**
128  * Sort categories by ID.
129  *
130  * Used by usort() as a callback, should not be used directly. Can actually be
131  * used to sort any term object.
132  *
133  * @since 2.3.0
134  * @access private
135  *
136  * @param object $a
137  * @param object $b
138  * @return int
139  */
140 function _usort_terms_by_ID( $a, $b ) {
141         if ( $a->term_id > $b->term_id )
142                 return 1;
143         elseif ( $a->term_id < $b->term_id )
144                 return -1;
145         else
146                 return 0;
147 }
148
149 /**
150  * Retrieve category name based on category ID.
151  *
152  * @since 0.71
153  *
154  * @param int $cat_ID Category ID.
155  * @return string Category name.
156  */
157 function get_the_category_by_ID( $cat_ID ) {
158         $cat_ID = (int) $cat_ID;
159         $category = &get_category( $cat_ID );
160         if ( is_wp_error( $category ) )
161                 return $category;
162         return $category->name;
163 }
164
165 /**
166  * Retrieve category list in either HTML list or custom format.
167  *
168  * @since 1.5.1
169  *
170  * @param string $separator Optional, default is empty string. Separator for between the categories.
171  * @param string $parents Optional. How to display the parents.
172  * @param int $post_id Optional. Post ID to retrieve categories.
173  * @return string
174  */
175 function get_the_category_list( $separator = '', $parents='', $post_id = false ) {
176         global $wp_rewrite;
177         $categories = get_the_category( $post_id );
178         if ( !is_object_in_taxonomy( get_post_type( $post_id ), 'category' ) )
179                 return apply_filters( 'the_category', '', $separator, $parents );
180
181         if ( empty( $categories ) )
182                 return apply_filters( 'the_category', __( 'Uncategorized' ), $separator, $parents );
183
184         $rel = ( is_object( $wp_rewrite ) && $wp_rewrite->using_permalinks() ) ? 'rel="category tag"' : 'rel="category"';
185
186         $thelist = '';
187         if ( '' == $separator ) {
188                 $thelist .= '<ul class="post-categories">';
189                 foreach ( $categories as $category ) {
190                         $thelist .= "\n\t<li>";
191                         switch ( strtolower( $parents ) ) {
192                                 case 'multiple':
193                                         if ( $category->parent )
194                                                 $thelist .= get_category_parents( $category->parent, true, $separator );
195                                         $thelist .= '<a href="' . get_category_link( $category->term_id ) . '" title="' . esc_attr( sprintf( __( "View all posts in %s" ), $category->name ) ) . '" ' . $rel . '>' . $category->name.'</a></li>';
196                                         break;
197                                 case 'single':
198                                         $thelist .= '<a href="' . get_category_link( $category->term_id ) . '" title="' . esc_attr( sprintf( __( "View all posts in %s" ), $category->name ) ) . '" ' . $rel . '>';
199                                         if ( $category->parent )
200                                                 $thelist .= get_category_parents( $category->parent, false, $separator );
201                                         $thelist .= $category->name.'</a></li>';
202                                         break;
203                                 case '':
204                                 default:
205                                         $thelist .= '<a href="' . get_category_link( $category->term_id ) . '" title="' . esc_attr( sprintf( __( "View all posts in %s" ), $category->name ) ) . '" ' . $rel . '>' . $category->cat_name.'</a></li>';
206                         }
207                 }
208                 $thelist .= '</ul>';
209         } else {
210                 $i = 0;
211                 foreach ( $categories as $category ) {
212                         if ( 0 < $i )
213                                 $thelist .= $separator;
214                         switch ( strtolower( $parents ) ) {
215                                 case 'multiple':
216                                         if ( $category->parent )
217                                                 $thelist .= get_category_parents( $category->parent, true, $separator );
218                                         $thelist .= '<a href="' . get_category_link( $category->term_id ) . '" title="' . esc_attr( sprintf( __( "View all posts in %s" ), $category->name ) ) . '" ' . $rel . '>' . $category->cat_name.'</a>';
219                                         break;
220                                 case 'single':
221                                         $thelist .= '<a href="' . get_category_link( $category->term_id ) . '" title="' . esc_attr( sprintf( __( "View all posts in %s" ), $category->name ) ) . '" ' . $rel . '>';
222                                         if ( $category->parent )
223                                                 $thelist .= get_category_parents( $category->parent, false, $separator );
224                                         $thelist .= "$category->cat_name</a>";
225                                         break;
226                                 case '':
227                                 default:
228                                         $thelist .= '<a href="' . get_category_link( $category->term_id ) . '" title="' . esc_attr( sprintf( __( "View all posts in %s" ), $category->name ) ) . '" ' . $rel . '>' . $category->name.'</a>';
229                         }
230                         ++$i;
231                 }
232         }
233         return apply_filters( 'the_category', $thelist, $separator, $parents );
234 }
235
236
237 /**
238  * Check if the current post in within any of the given categories.
239  *
240  * The given categories are checked against the post's categories' term_ids, names and slugs.
241  * Categories given as integers will only be checked against the post's categories' term_ids.
242  *
243  * Prior to v2.5 of WordPress, category names were not supported.
244  * Prior to v2.7, category slugs were not supported.
245  * Prior to v2.7, only one category could be compared: in_category( $single_category ).
246  * Prior to v2.7, this function could only be used in the WordPress Loop.
247  * As of 2.7, the function can be used anywhere if it is provided a post ID or post object.
248  *
249  * @since 1.2.0
250  *
251  * @uses is_object_in_term()
252  *
253  * @param int|string|array $category. Category ID, name or slug, or array of said.
254  * @param int|post object Optional.  Post to check instead of the current post. @since 2.7.0
255  * @return bool True if the current post is in any of the given categories.
256  */
257 function in_category( $category, $_post = null ) {
258         if ( empty( $category ) )
259                 return false;
260
261         if ( $_post ) {
262                 $_post = get_post( $_post );
263         } else {
264                 $_post =& $GLOBALS['post'];
265         }
266
267         if ( !$_post )
268                 return false;
269
270         $r = is_object_in_term( $_post->ID, 'category', $category );
271         if ( is_wp_error( $r ) )
272                 return false;
273         return $r;
274 }
275
276 /**
277  * Display the category list for the post.
278  *
279  * @since 0.71
280  *
281  * @param string $separator Optional, default is empty string. Separator for between the categories.
282  * @param string $parents Optional. How to display the parents.
283  * @param int $post_id Optional. Post ID to retrieve categories.
284  */
285 function the_category( $separator = '', $parents='', $post_id = false ) {
286         echo get_the_category_list( $separator, $parents, $post_id );
287 }
288
289 /**
290  * Retrieve category description.
291  *
292  * @since 1.0.0
293  *
294  * @param int $category Optional. Category ID. Will use global category ID by default.
295  * @return string Category description, available.
296  */
297 function category_description( $category = 0 ) {
298         return term_description( $category, 'category' );
299 }
300
301 /**
302  * Display or retrieve the HTML dropdown list of categories.
303  *
304  * The list of arguments is below:
305  *     'show_option_all' (string) - Text to display for showing all categories.
306  *     'show_option_none' (string) - Text to display for showing no categories.
307  *     'orderby' (string) default is 'ID' - What column to use for ordering the
308  * categories.
309  *     'order' (string) default is 'ASC' - What direction to order categories.
310  *     'show_last_update' (bool|int) default is 0 - See {@link get_categories()}
311  *     'show_count' (bool|int) default is 0 - Whether to show how many posts are
312  * in the category.
313  *     'hide_empty' (bool|int) default is 1 - Whether to hide categories that
314  * don't have any posts attached to them.
315  *     'child_of' (int) default is 0 - See {@link get_categories()}.
316  *     'exclude' (string) - See {@link get_categories()}.
317  *     'echo' (bool|int) default is 1 - Whether to display or retrieve content.
318  *     'depth' (int) - The max depth.
319  *     'tab_index' (int) - Tab index for select element.
320  *     'name' (string) - The name attribute value for select element.
321  *     'id' (string) - The ID attribute value for select element. Defaults to name if omitted.
322  *     'class' (string) - The class attribute value for select element.
323  *     'selected' (int) - Which category ID is selected.
324  *     'taxonomy' (string) - The name of the taxonomy to retrieve. Defaults to category.
325  *
326  * The 'hierarchical' argument, which is disabled by default, will override the
327  * depth argument, unless it is true. When the argument is false, it will
328  * display all of the categories. When it is enabled it will use the value in
329  * the 'depth' argument.
330  *
331  * @since 2.1.0
332  *
333  * @param string|array $args Optional. Override default arguments.
334  * @return string HTML content only if 'echo' argument is 0.
335  */
336 function wp_dropdown_categories( $args = '' ) {
337         $defaults = array(
338                 'show_option_all' => '', 'show_option_none' => '',
339                 'orderby' => 'id', 'order' => 'ASC',
340                 'show_last_update' => 0, 'show_count' => 0,
341                 'hide_empty' => 1, 'child_of' => 0,
342                 'exclude' => '', 'echo' => 1,
343                 'selected' => 0, 'hierarchical' => 0,
344                 'name' => 'cat', 'id' => '',
345                 'class' => 'postform', 'depth' => 0,
346                 'tab_index' => 0, 'taxonomy' => 'category',
347                 'hide_if_empty' => false
348         );
349
350         $defaults['selected'] = ( is_category() ) ? get_query_var( 'cat' ) : 0;
351
352         // Back compat.
353         if ( isset( $args['type'] ) && 'link' == $args['type'] ) {
354                 _deprecated_argument( __FUNCTION__, '3.0', '' );
355                 $args['taxonomy'] = 'link_category';
356         }
357
358         $r = wp_parse_args( $args, $defaults );
359
360         if ( !isset( $r['pad_counts'] ) && $r['show_count'] && $r['hierarchical'] ) {
361                 $r['pad_counts'] = true;
362         }
363
364         $r['include_last_update_time'] = $r['show_last_update'];
365         extract( $r );
366
367         $tab_index_attribute = '';
368         if ( (int) $tab_index > 0 )
369                 $tab_index_attribute = " tabindex=\"$tab_index\"";
370
371         $categories = get_terms( $taxonomy, $r );
372         $name = esc_attr( $name );
373         $class = esc_attr( $class );
374         $id = $id ? esc_attr( $id ) : $name;
375
376         if ( ! $r['hide_if_empty'] || ! empty($categories) )
377                 $output = "<select name='$name' id='$id' class='$class' $tab_index_attribute>\n";
378         else
379                 $output = '';
380
381         if ( empty($categories) && ! $r['hide_if_empty'] && !empty($show_option_none) ) {
382                 $show_option_none = apply_filters( 'list_cats', $show_option_none );
383                 $output .= "\t<option value='-1' selected='selected'>$show_option_none</option>\n";
384         }
385
386         if ( ! empty( $categories ) ) {
387
388                 if ( $show_option_all ) {
389                         $show_option_all = apply_filters( 'list_cats', $show_option_all );
390                         $selected = ( '0' === strval($r['selected']) ) ? " selected='selected'" : '';
391                         $output .= "\t<option value='0'$selected>$show_option_all</option>\n";
392                 }
393
394                 if ( $show_option_none ) {
395                         $show_option_none = apply_filters( 'list_cats', $show_option_none );
396                         $selected = ( '-1' === strval($r['selected']) ) ? " selected='selected'" : '';
397                         $output .= "\t<option value='-1'$selected>$show_option_none</option>\n";
398                 }
399
400                 if ( $hierarchical )
401                         $depth = $r['depth'];  // Walk the full depth.
402                 else
403                         $depth = -1; // Flat.
404
405                 $output .= walk_category_dropdown_tree( $categories, $depth, $r );
406         }
407         if ( ! $r['hide_if_empty'] || ! empty($categories) )
408                 $output .= "</select>\n";
409
410
411         $output = apply_filters( 'wp_dropdown_cats', $output );
412
413         if ( $echo )
414                 echo $output;
415
416         return $output;
417 }
418
419 /**
420  * Display or retrieve the HTML list of categories.
421  *
422  * The list of arguments is below:
423  *     'show_option_all' (string) - Text to display for showing all categories.
424  *     'orderby' (string) default is 'ID' - What column to use for ordering the
425  * categories.
426  *     'order' (string) default is 'ASC' - What direction to order categories.
427  *     'show_last_update' (bool|int) default is 0 - See {@link
428  * walk_category_dropdown_tree()}
429  *     'show_count' (bool|int) default is 0 - Whether to show how many posts are
430  * in the category.
431  *     'hide_empty' (bool|int) default is 1 - Whether to hide categories that
432  * don't have any posts attached to them.
433  *     'use_desc_for_title' (bool|int) default is 1 - Whether to use the
434  * description instead of the category title.
435  *     'feed' - See {@link get_categories()}.
436  *     'feed_type' - See {@link get_categories()}.
437  *     'feed_image' - See {@link get_categories()}.
438  *     'child_of' (int) default is 0 - See {@link get_categories()}.
439  *     'exclude' (string) - See {@link get_categories()}.
440  *     'exclude_tree' (string) - See {@link get_categories()}.
441  *     'echo' (bool|int) default is 1 - Whether to display or retrieve content.
442  *     'current_category' (int) - See {@link get_categories()}.
443  *     'hierarchical' (bool) - See {@link get_categories()}.
444  *     'title_li' (string) - See {@link get_categories()}.
445  *     'depth' (int) - The max depth.
446  *
447  * @since 2.1.0
448  *
449  * @param string|array $args Optional. Override default arguments.
450  * @return string HTML content only if 'echo' argument is 0.
451  */
452 function wp_list_categories( $args = '' ) {
453         $defaults = array(
454                 'show_option_all' => '', 'show_option_none' => __('No categories'),
455                 'orderby' => 'name', 'order' => 'ASC',
456                 'show_last_update' => 0, 'style' => 'list',
457                 'show_count' => 0, 'hide_empty' => 1,
458                 'use_desc_for_title' => 1, 'child_of' => 0,
459                 'feed' => '', 'feed_type' => '',
460                 'feed_image' => '', 'exclude' => '',
461                 'exclude_tree' => '', 'current_category' => 0,
462                 'hierarchical' => true, 'title_li' => __( 'Categories' ),
463                 'echo' => 1, 'depth' => 0,
464                 'taxonomy' => 'category'
465         );
466
467         $r = wp_parse_args( $args, $defaults );
468
469         if ( !isset( $r['pad_counts'] ) && $r['show_count'] && $r['hierarchical'] )
470                 $r['pad_counts'] = true;
471
472         if ( isset( $r['show_date'] ) )
473                 $r['include_last_update_time'] = $r['show_date'];
474
475         if ( true == $r['hierarchical'] ) {
476                 $r['exclude_tree'] = $r['exclude'];
477                 $r['exclude'] = '';
478         }
479
480         if ( !isset( $r['class'] ) )
481                 $r['class'] = ( 'category' == $r['taxonomy'] ) ? 'categories' : $r['taxonomy'];
482
483         extract( $r );
484
485         if ( !taxonomy_exists($taxonomy) )
486                 return false;
487
488         $categories = get_categories( $r );
489
490         $output = '';
491         if ( $title_li && 'list' == $style )
492                         $output = '<li class="' . $class . '">' . $title_li . '<ul>';
493
494         if ( empty( $categories ) ) {
495                 if ( ! empty( $show_option_none ) ) {
496                         if ( 'list' == $style )
497                                 $output .= '<li>' . $show_option_none . '</li>';
498                         else
499                                 $output .= $show_option_none;
500                 }
501         } else {
502                 global $wp_query;
503
504                 if( !empty( $show_option_all ) )
505                         if ( 'list' == $style )
506                                 $output .= '<li><a href="' .  get_bloginfo( 'url' )  . '">' . $show_option_all . '</a></li>';
507                         else
508                                 $output .= '<a href="' .  get_bloginfo( 'url' )  . '">' . $show_option_all . '</a>';
509
510                 if ( empty( $r['current_category'] ) && ( is_category() || is_tax() ) )
511                         $r['current_category'] = $wp_query->get_queried_object_id();
512
513                 if ( $hierarchical )
514                         $depth = $r['depth'];
515                 else
516                         $depth = -1; // Flat.
517
518                 $output .= walk_category_tree( $categories, $depth, $r );
519         }
520
521         if ( $title_li && 'list' == $style )
522                 $output .= '</ul></li>';
523
524         $output = apply_filters( 'wp_list_categories', $output, $args );
525
526         if ( $echo )
527                 echo $output;
528         else
529                 return $output;
530 }
531
532 /**
533  * Display tag cloud.
534  *
535  * The text size is set by the 'smallest' and 'largest' arguments, which will
536  * use the 'unit' argument value for the CSS text size unit. The 'format'
537  * argument can be 'flat' (default), 'list', or 'array'. The flat value for the
538  * 'format' argument will separate tags with spaces. The list value for the
539  * 'format' argument will format the tags in a UL HTML list. The array value for
540  * the 'format' argument will return in PHP array type format.
541  *
542  * The 'orderby' argument will accept 'name' or 'count' and defaults to 'name'.
543  * The 'order' is the direction to sort, defaults to 'ASC' and can be 'DESC'.
544  *
545  * The 'number' argument is how many tags to return. By default, the limit will
546  * be to return the top 45 tags in the tag cloud list.
547  *
548  * The 'topic_count_text_callback' argument is a function, which, given the count
549  * of the posts  with that tag, returns a text for the tooltip of the tag link.
550  *
551  * The 'exclude' and 'include' arguments are used for the {@link get_tags()}
552  * function. Only one should be used, because only one will be used and the
553  * other ignored, if they are both set.
554  *
555  * @since 2.3.0
556  *
557  * @param array|string $args Optional. Override default arguments.
558  * @return array Generated tag cloud, only if no failures and 'array' is set for the 'format' argument.
559  */
560 function wp_tag_cloud( $args = '' ) {
561         $defaults = array(
562                 'smallest' => 8, 'largest' => 22, 'unit' => 'pt', 'number' => 45,
563                 'format' => 'flat', 'separator' => "\n", 'orderby' => 'name', 'order' => 'ASC',
564                 'exclude' => '', 'include' => '', 'link' => 'view', 'taxonomy' => 'post_tag', 'echo' => true
565         );
566         $args = wp_parse_args( $args, $defaults );
567
568         $tags = get_terms( $args['taxonomy'], array_merge( $args, array( 'orderby' => 'count', 'order' => 'DESC' ) ) ); // Always query top tags
569
570         if ( empty( $tags ) )
571                 return;
572
573         foreach ( $tags as $key => $tag ) {
574                 if ( 'edit' == $args['link'] )
575                         $link = get_edit_tag_link( $tag->term_id, $args['taxonomy'] );
576                 else
577                         $link = get_term_link( intval($tag->term_id), $args['taxonomy'] );
578                 if ( is_wp_error( $link ) )
579                         return false;
580
581                 $tags[ $key ]->link = $link;
582                 $tags[ $key ]->id = $tag->term_id;
583         }
584
585         $return = wp_generate_tag_cloud( $tags, $args ); // Here's where those top tags get sorted according to $args
586
587         $return = apply_filters( 'wp_tag_cloud', $return, $args );
588
589         if ( 'array' == $args['format'] || empty($args['echo']) )
590                 return $return;
591
592         echo $return;
593 }
594
595 /**
596  * Default text for tooltip for tag links
597  *
598  * @param integer $count number of posts with that tag
599  * @return string text for the tooltip of a tag link.
600  */
601 function default_topic_count_text( $count ) {
602         return sprintf( _n('%s topic', '%s topics', $count), number_format_i18n( $count ) );
603 }
604
605 /**
606  * Default topic count scaling for tag links
607  *
608  * @param integer $count number of posts with that tag
609  * @return integer scaled count
610  */
611 function default_topic_count_scale( $count ) {
612         return round(log10($count + 1) * 100);
613 }
614
615
616 /**
617  * Generates a tag cloud (heatmap) from provided data.
618  *
619  * The text size is set by the 'smallest' and 'largest' arguments, which will
620  * use the 'unit' argument value for the CSS text size unit. The 'format'
621  * argument can be 'flat' (default), 'list', or 'array'. The flat value for the
622  * 'format' argument will separate tags with spaces. The list value for the
623  * 'format' argument will format the tags in a UL HTML list. The array value for
624  * the 'format' argument will return in PHP array type format.
625  *
626  * The 'tag_cloud_sort' filter allows you to override the sorting.
627  * Passed to the filter: $tags array and $args array, has to return the $tags array
628  * after sorting it.
629  *
630  * The 'orderby' argument will accept 'name' or 'count' and defaults to 'name'.
631  * The 'order' is the direction to sort, defaults to 'ASC' and can be 'DESC' or
632  * 'RAND'.
633  *
634  * The 'number' argument is how many tags to return. By default, the limit will
635  * be to return the entire tag cloud list.
636  *
637  * The 'topic_count_text_callback' argument is a function, which given the count
638  * of the posts  with that tag returns a text for the tooltip of the tag link.
639  *
640  * @todo Complete functionality.
641  * @since 2.3.0
642  *
643  * @param array $tags List of tags.
644  * @param string|array $args Optional, override default arguments.
645  * @return string
646  */
647 function wp_generate_tag_cloud( $tags, $args = '' ) {
648         global $wp_rewrite;
649         $defaults = array(
650                 'smallest' => 8, 'largest' => 22, 'unit' => 'pt', 'number' => 0,
651                 'format' => 'flat', 'separator' => "\n", 'orderby' => 'name', 'order' => 'ASC',
652                 'topic_count_text_callback' => 'default_topic_count_text',
653                 'topic_count_scale_callback' => 'default_topic_count_scale', 'filter' => 1,
654         );
655
656         if ( !isset( $args['topic_count_text_callback'] ) && isset( $args['single_text'] ) && isset( $args['multiple_text'] ) ) {
657                 $body = 'return sprintf (
658                         _n(' . var_export($args['single_text'], true) . ', ' . var_export($args['multiple_text'], true) . ', $count),
659                         number_format_i18n( $count ));';
660                 $args['topic_count_text_callback'] = create_function('$count', $body);
661         }
662
663         $args = wp_parse_args( $args, $defaults );
664         extract( $args );
665
666         if ( empty( $tags ) )
667                 return;
668
669         $tags_sorted = apply_filters( 'tag_cloud_sort', $tags, $args );
670         if ( $tags_sorted != $tags  ) { // the tags have been sorted by a plugin
671                 $tags = $tags_sorted;
672                 unset($tags_sorted);
673         } else {
674                 if ( 'RAND' == $order ) {
675                         shuffle($tags);
676                 } else {
677                         // SQL cannot save you; this is a second (potentially different) sort on a subset of data.
678                         if ( 'name' == $orderby )
679                                 uasort( $tags, create_function('$a, $b', 'return strnatcasecmp($a->name, $b->name);') );
680                         else
681                                 uasort( $tags, create_function('$a, $b', 'return ($a->count > $b->count);') );
682
683                         if ( 'DESC' == $order )
684                                 $tags = array_reverse( $tags, true );
685                 }
686         }
687
688         if ( $number > 0 )
689                 $tags = array_slice($tags, 0, $number);
690
691         $counts = array();
692         $real_counts = array(); // For the alt tag
693         foreach ( (array) $tags as $key => $tag ) {
694                 $real_counts[ $key ] = $tag->count;
695                 $counts[ $key ] = $topic_count_scale_callback($tag->count);
696         }
697
698         $min_count = min( $counts );
699         $spread = max( $counts ) - $min_count;
700         if ( $spread <= 0 )
701                 $spread = 1;
702         $font_spread = $largest - $smallest;
703         if ( $font_spread < 0 )
704                 $font_spread = 1;
705         $font_step = $font_spread / $spread;
706
707         $a = array();
708
709         foreach ( $tags as $key => $tag ) {
710                 $count = $counts[ $key ];
711                 $real_count = $real_counts[ $key ];
712                 $tag_link = '#' != $tag->link ? esc_url( $tag->link ) : '#';
713                 $tag_id = isset($tags[ $key ]->id) ? $tags[ $key ]->id : $key;
714                 $tag_name = $tags[ $key ]->name;
715                 $a[] = "<a href='$tag_link' class='tag-link-$tag_id' title='" . esc_attr( $topic_count_text_callback( $real_count ) ) . "' style='font-size: " .
716                         ( $smallest + ( ( $count - $min_count ) * $font_step ) )
717                         . "$unit;'>$tag_name</a>";
718         }
719
720         switch ( $format ) :
721         case 'array' :
722                 $return =& $a;
723                 break;
724         case 'list' :
725                 $return = "<ul class='wp-tag-cloud'>\n\t<li>";
726                 $return .= join( "</li>\n\t<li>", $a );
727                 $return .= "</li>\n</ul>\n";
728                 break;
729         default :
730                 $return = join( $separator, $a );
731                 break;
732         endswitch;
733
734     if ( $filter )
735                 return apply_filters( 'wp_generate_tag_cloud', $return, $tags, $args );
736     else
737                 return $return;
738 }
739
740 //
741 // Helper functions
742 //
743
744 /**
745  * Retrieve HTML list content for category list.
746  *
747  * @uses Walker_Category to create HTML list content.
748  * @since 2.1.0
749  * @see Walker_Category::walk() for parameters and return description.
750  */
751 function walk_category_tree() {
752         $args = func_get_args();
753         // the user's options are the third parameter
754         if ( empty($args[2]['walker']) || !is_a($args[2]['walker'], 'Walker') )
755                 $walker = new Walker_Category;
756         else
757                 $walker = $args[2]['walker'];
758
759         return call_user_func_array(array( &$walker, 'walk' ), $args );
760 }
761
762 /**
763  * Retrieve HTML dropdown (select) content for category list.
764  *
765  * @uses Walker_CategoryDropdown to create HTML dropdown content.
766  * @since 2.1.0
767  * @see Walker_CategoryDropdown::walk() for parameters and return description.
768  */
769 function walk_category_dropdown_tree() {
770         $args = func_get_args();
771         // the user's options are the third parameter
772         if ( empty($args[2]['walker']) || !is_a($args[2]['walker'], 'Walker') )
773                 $walker = new Walker_CategoryDropdown;
774         else
775                 $walker = $args[2]['walker'];
776
777         return call_user_func_array(array( &$walker, 'walk' ), $args );
778 }
779
780 //
781 // Tags
782 //
783
784 /**
785  * Retrieve the link to the tag.
786  *
787  * @since 2.3.0
788  * @uses apply_filters() Calls 'tag_link' with tag link and tag ID as parameters.
789  *
790  * @param int $tag_id Tag (term) ID.
791  * @return string
792  */
793 function get_tag_link( $tag_id ) {
794         global $wp_rewrite;
795         $taglink = $wp_rewrite->get_tag_permastruct();
796
797         $tag = &get_term( $tag_id, 'post_tag' );
798         if ( is_wp_error( $tag ) )
799                 return $tag;
800         $slug = $tag->slug;
801
802         if ( empty( $taglink ) ) {
803                 $file = get_option( 'home' ) . '/';
804                 $taglink = $file . '?tag=' . $slug;
805         } else {
806                 $taglink = str_replace( '%tag%', $slug, $taglink );
807                 $taglink = get_option( 'home' ) . user_trailingslashit( $taglink, 'category' );
808         }
809         return apply_filters( 'tag_link', $taglink, $tag_id );
810 }
811
812 /**
813  * Retrieve the tags for a post.
814  *
815  * @since 2.3.0
816  * @uses apply_filters() Calls 'get_the_tags' filter on the list of post tags.
817  *
818  * @param int $id Post ID.
819  * @return array
820  */
821 function get_the_tags( $id = 0 ) {
822         return apply_filters( 'get_the_tags', get_the_terms( $id, 'post_tag' ) );
823 }
824
825 /**
826  * Retrieve the tags for a post formatted as a string.
827  *
828  * @since 2.3.0
829  * @uses apply_filters() Calls 'the_tags' filter on string list of tags.
830  *
831  * @param string $before Optional. Before tags.
832  * @param string $sep Optional. Between tags.
833  * @param string $after Optional. After tags.
834  * @return string
835  */
836 function get_the_tag_list( $before = '', $sep = '', $after = '' ) {
837         return apply_filters( 'the_tags', get_the_term_list( 0, 'post_tag', $before, $sep, $after ), $before, $sep, $after);
838 }
839
840 /**
841  * Retrieve the tags for a post.
842  *
843  * @since 2.3.0
844  *
845  * @param string $before Optional. Before list.
846  * @param string $sep Optional. Separate items using this.
847  * @param string $after Optional. After list.
848  * @return string
849  */
850 function the_tags( $before = null, $sep = ', ', $after = '' ) {
851         if ( null === $before )
852                 $before = __('Tags: ');
853         echo get_the_tag_list($before, $sep, $after);
854 }
855
856 /**
857  * Retrieve tag description.
858  *
859  * @since 2.8
860  *
861  * @param int $tag Optional. Tag ID. Will use global tag ID by default.
862  * @return string Tag description, available.
863  */
864 function tag_description( $tag = 0 ) {
865         return term_description( $tag );
866 }
867
868 /**
869  * Retrieve term description.
870  *
871  * @since 2.8
872  *
873  * @param int $term Optional. Term ID. Will use global term ID by default.
874  * @return string Term description, available.
875  */
876 function term_description( $term = 0, $taxonomy = 'post_tag' ) {
877         if ( !$term && ( is_tax() || is_tag() || is_category() ) ) {
878                 global $wp_query;
879                 $term = $wp_query->get_queried_object();
880                 $taxonomy = $term->taxonomy;
881                 $term = $term->term_id;
882         }
883         $description = get_term_field( 'description', $term, $taxonomy );
884         return is_wp_error( $description ) ? '' : $description;
885 }
886
887 /**
888  * Retrieve the terms of the taxonomy that are attached to the post.
889  *
890  * This function can only be used within the loop.
891  *
892  * @since 2.5.0
893  *
894  * @param int $id Post ID. Is not optional.
895  * @param string $taxonomy Taxonomy name.
896  * @return array|bool False on failure. Array of term objects on success.
897  */
898 function get_the_terms( $id = 0, $taxonomy ) {
899         global $post;
900
901         $id = (int) $id;
902
903         if ( !$id ) {
904                 if ( !$post->ID )
905                         return false;
906                 else
907                         $id = (int) $post->ID;
908         }
909
910         $terms = get_object_term_cache( $id, $taxonomy );
911         if ( false === $terms )
912                 $terms = wp_get_object_terms( $id, $taxonomy );
913
914         if ( empty( $terms ) )
915                 return false;
916
917         return $terms;
918 }
919
920 /**
921  * Retrieve a post's terms as a list with specified format.
922  *
923  * @since 2.5.0
924  *
925  * @param int $id Post ID.
926  * @param string $taxonomy Taxonomy name.
927  * @param string $before Optional. Before list.
928  * @param string $sep Optional. Separate items using this.
929  * @param string $after Optional. After list.
930  * @return string
931  */
932 function get_the_term_list( $id = 0, $taxonomy, $before = '', $sep = '', $after = '' ) {
933         $terms = get_the_terms( $id, $taxonomy );
934
935         if ( is_wp_error( $terms ) )
936                 return $terms;
937
938         if ( empty( $terms ) )
939                 return false;
940
941         foreach ( $terms as $term ) {
942                 $link = get_term_link( $term, $taxonomy );
943                 if ( is_wp_error( $link ) )
944                         return $link;
945                 $term_links[] = '<a href="' . $link . '" rel="tag">' . $term->name . '</a>';
946         }
947
948         $term_links = apply_filters( "term_links-$taxonomy", $term_links );
949
950         return $before . join( $sep, $term_links ) . $after;
951 }
952
953 /**
954  * Display the terms in a list.
955  *
956  * @since 2.5.0
957  *
958  * @param int $id Term ID.
959  * @param string $taxonomy Taxonomy name.
960  * @param string $before Optional. Before list.
961  * @param string $sep Optional. Separate items using this.
962  * @param string $after Optional. After list.
963  * @return null|bool False on WordPress error. Returns null when displaying.
964  */
965 function the_terms( $id, $taxonomy, $before = '', $sep = ', ', $after = '' ) {
966         $term_list = get_the_term_list( $id, $taxonomy, $before, $sep, $after );
967
968         if ( is_wp_error( $term_list ) )
969                 return false;
970
971         echo apply_filters('the_terms', $term_list, $taxonomy, $before, $sep, $after);
972 }
973
974 /**
975  * Check if the current post has any of given tags.
976  *
977  * The given tags are checked against the post's tags' term_ids, names and slugs.
978  * Tags given as integers will only be checked against the post's tags' term_ids.
979  * If no tags are given, determines if post has any tags.
980  *
981  * Prior to v2.7 of WordPress, tags given as integers would also be checked against the post's tags' names and slugs (in addition to term_ids)
982  * Prior to v2.7, this function could only be used in the WordPress Loop.
983  * As of 2.7, the function can be used anywhere if it is provided a post ID or post object.
984  *
985  * @since 2.6.0
986  *
987  * @uses is_object_in_term()
988  *
989  * @param string|int|array $tag Optional. The tag name/term_id/slug or array of them to check for.
990  * @param int|post object Optional.  Post to check instead of the current post. @since 2.7.0
991  * @return bool True if the current post has any of the the given tags (or any tag, if no tag specified).
992  */
993 function has_tag( $tag = '', $_post = null ) {
994         if ( $_post ) {
995                 $_post = get_post( $_post );
996         } else {
997                 $_post =& $GLOBALS['post'];
998         }
999
1000         if ( !$_post )
1001                 return false;
1002
1003         $r = is_object_in_term( $_post->ID, 'post_tag', $tag );
1004         if ( is_wp_error( $r ) )
1005                 return false;
1006         return $r;
1007 }
1008
1009 ?>