Issues (2010)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

wp-includes/category-template.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/**
3
 * Taxonomy API: Core category-specific template tags
4
 *
5
 * @package WordPress
6
 * @subpackage Template
7
 * @since 1.2.0
8
 */
9
10
/**
11
 * Retrieve category link URL.
12
 *
13
 * @since 1.0.0
14
 * @see get_term_link()
15
 *
16
 * @param int|object $category Category ID or object.
17
 * @return string Link on success, empty string if category does not exist.
18
 */
19 View Code Duplication
function get_category_link( $category ) {
20
	if ( ! is_object( $category ) )
21
		$category = (int) $category;
22
23
	$category = get_term_link( $category, 'category' );
24
25
	if ( is_wp_error( $category ) )
26
		return '';
27
28
	return $category;
29
}
30
31
/**
32
 * Retrieve category parents with separator.
33
 *
34
 * @since 1.2.0
35
 *
36
 * @param int $id Category ID.
37
 * @param bool $link Optional, default is false. Whether to format with link.
38
 * @param string $separator Optional, default is '/'. How to separate categories.
39
 * @param bool $nicename Optional, default is false. Whether to use nice name for display.
40
 * @param array $visited Optional. Already linked to categories to prevent duplicates.
41
 * @return string|WP_Error A list of category parents on success, WP_Error on failure.
42
 */
43
function get_category_parents( $id, $link = false, $separator = '/', $nicename = false, $visited = array() ) {
44
	$chain = '';
45
	$parent = get_term( $id, 'category' );
46
	if ( is_wp_error( $parent ) )
47
		return $parent;
48
49
	if ( $nicename )
50
		$name = $parent->slug;
51
	else
52
		$name = $parent->name;
53
54
	if ( $parent->parent && ( $parent->parent != $parent->term_id ) && !in_array( $parent->parent, $visited ) ) {
55
		$visited[] = $parent->parent;
56
		$chain .= get_category_parents( $parent->parent, $link, $separator, $nicename, $visited );
57
	}
58
59
	if ( $link )
60
		$chain .= '<a href="' . esc_url( get_category_link( $parent->term_id ) ) . '">'.$name.'</a>' . $separator;
61
	else
62
		$chain .= $name.$separator;
63
	return $chain;
64
}
65
66
/**
67
 * Retrieve post categories.
68
 *
69
 * This tag may be used outside The Loop by passing a post id as the parameter.
70
 *
71
 * Note: This function only returns results from the default "category" taxonomy.
72
 * For custom taxonomies use get_the_terms().
73
 *
74
 * @since 0.71
75
 *
76
 * @param int $id Optional, default to current post ID. The post ID.
77
 * @return array Array of WP_Term objects, one for each category assigned to the post.
78
 */
79
function get_the_category( $id = false ) {
80
	$categories = get_the_terms( $id, 'category' );
0 ignored issues
show
It seems like $id defined by parameter $id on line 79 can also be of type false; however, get_the_terms() does only seem to accept integer|object, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
81
	if ( ! $categories || is_wp_error( $categories ) )
82
		$categories = array();
83
84
	$categories = array_values( $categories );
85
86
	foreach ( array_keys( $categories ) as $key ) {
87
		_make_cat_compat( $categories[$key] );
88
	}
89
90
	/**
91
	 * Filters the array of categories to return for a post.
92
	 *
93
	 * @since 3.1.0
94
	 * @since 4.4.0 Added `$id` parameter.
95
	 *
96
	 * @param array $categories An array of categories to return for the post.
97
	 * @param int   $id         ID of the post.
98
	 */
99
	return apply_filters( 'get_the_categories', $categories, $id );
100
}
101
102
/**
103
 * Sort categories by name.
104
 *
105
 * Used by usort() as a callback, should not be used directly. Can actually be
106
 * used to sort any term object.
107
 *
108
 * @since 2.3.0
109
 * @access private
110
 *
111
 * @param object $a
112
 * @param object $b
113
 * @return int
114
 */
115
function _usort_terms_by_name( $a, $b ) {
116
	return strcmp( $a->name, $b->name );
117
}
118
119
/**
120
 * Sort categories by ID.
121
 *
122
 * Used by usort() as a callback, should not be used directly. Can actually be
123
 * used to sort any term object.
124
 *
125
 * @since 2.3.0
126
 * @access private
127
 *
128
 * @param object $a
129
 * @param object $b
130
 * @return int
131
 */
132
function _usort_terms_by_ID( $a, $b ) {
133
	if ( $a->term_id > $b->term_id )
134
		return 1;
135
	elseif ( $a->term_id < $b->term_id )
136
		return -1;
137
	else
138
		return 0;
139
}
140
141
/**
142
 * Retrieve category name based on category ID.
143
 *
144
 * @since 0.71
145
 *
146
 * @param int $cat_ID Category ID.
147
 * @return string|WP_Error Category name on success, WP_Error on failure.
148
 */
149 View Code Duplication
function get_the_category_by_ID( $cat_ID ) {
150
	$cat_ID = (int) $cat_ID;
151
	$category = get_term( $cat_ID, 'category' );
152
153
	if ( is_wp_error( $category ) )
154
		return $category;
155
156
	return ( $category ) ? $category->name : '';
157
}
158
159
/**
160
 * Retrieve category list in either HTML list or custom format.
161
 *
162
 * @since 1.5.1
163
 *
164
 * @global WP_Rewrite $wp_rewrite
165
 *
166
 * @param string $separator Optional, default is empty string. Separator for between the categories.
167
 * @param string $parents Optional. How to display the parents.
168
 * @param int $post_id Optional. Post ID to retrieve categories.
169
 * @return string
170
 */
171
function get_the_category_list( $separator = '', $parents='', $post_id = false ) {
172
	global $wp_rewrite;
173
	if ( ! is_object_in_taxonomy( get_post_type( $post_id ), 'category' ) ) {
174
		/** This filter is documented in wp-includes/category-template.php */
175
		return apply_filters( 'the_category', '', $separator, $parents );
176
	}
177
178
	/**
179
	 * Filters the categories before building the category list.
180
	 *
181
	 * @since 4.4.0
182
	 *
183
	 * @param array    $categories An array of the post's categories.
184
	 * @param int|bool $post_id    ID of the post we're retrieving categories for. When `false`, we assume the
185
	 *                             current post in the loop.
186
	 */
187
	$categories = apply_filters( 'the_category_list', get_the_category( $post_id ), $post_id );
188
189
	if ( empty( $categories ) ) {
190
		/** This filter is documented in wp-includes/category-template.php */
191
		return apply_filters( 'the_category', __( 'Uncategorized' ), $separator, $parents );
192
	}
193
194
	$rel = ( is_object( $wp_rewrite ) && $wp_rewrite->using_permalinks() ) ? 'rel="category tag"' : 'rel="category"';
195
196
	$thelist = '';
197
	if ( '' == $separator ) {
198
		$thelist .= '<ul class="post-categories">';
199
		foreach ( $categories as $category ) {
200
			$thelist .= "\n\t<li>";
201 View Code Duplication
			switch ( strtolower( $parents ) ) {
202
				case 'multiple':
203
					if ( $category->parent )
204
						$thelist .= get_category_parents( $category->parent, true, $separator );
205
					$thelist .= '<a href="' . esc_url( get_category_link( $category->term_id ) ) . '" ' . $rel . '>' . $category->name.'</a></li>';
206
					break;
207
				case 'single':
208
					$thelist .= '<a href="' . esc_url( get_category_link( $category->term_id ) ) . '"  ' . $rel . '>';
209
					if ( $category->parent )
210
						$thelist .= get_category_parents( $category->parent, false, $separator );
211
					$thelist .= $category->name.'</a></li>';
212
					break;
213
				case '':
214
				default:
215
					$thelist .= '<a href="' . esc_url( get_category_link( $category->term_id ) ) . '" ' . $rel . '>' . $category->name.'</a></li>';
216
			}
217
		}
218
		$thelist .= '</ul>';
219
	} else {
220
		$i = 0;
221
		foreach ( $categories as $category ) {
222
			if ( 0 < $i )
223
				$thelist .= $separator;
224 View Code Duplication
			switch ( strtolower( $parents ) ) {
225
				case 'multiple':
226
					if ( $category->parent )
227
						$thelist .= get_category_parents( $category->parent, true, $separator );
228
					$thelist .= '<a href="' . esc_url( get_category_link( $category->term_id ) ) . '" ' . $rel . '>' . $category->name.'</a>';
229
					break;
230
				case 'single':
231
					$thelist .= '<a href="' . esc_url( get_category_link( $category->term_id ) ) . '" ' . $rel . '>';
232
					if ( $category->parent )
233
						$thelist .= get_category_parents( $category->parent, false, $separator );
234
					$thelist .= "$category->name</a>";
235
					break;
236
				case '':
237
				default:
238
					$thelist .= '<a href="' . esc_url( get_category_link( $category->term_id ) ) . '" ' . $rel . '>' . $category->name.'</a>';
239
			}
240
			++$i;
241
		}
242
	}
243
244
	/**
245
	 * Filters the category or list of categories.
246
	 *
247
	 * @since 1.2.0
248
	 *
249
	 * @param array  $thelist   List of categories for the current post.
250
	 * @param string $separator Separator used between the categories.
251
	 * @param string $parents   How to display the category parents. Accepts 'multiple',
252
	 *                          'single', or empty.
253
	 */
254
	return apply_filters( 'the_category', $thelist, $separator, $parents );
255
}
256
257
/**
258
 * Check if the current post in within any of the given categories.
259
 *
260
 * The given categories are checked against the post's categories' term_ids, names and slugs.
261
 * Categories given as integers will only be checked against the post's categories' term_ids.
262
 *
263
 * Prior to v2.5 of WordPress, category names were not supported.
264
 * Prior to v2.7, category slugs were not supported.
265
 * Prior to v2.7, only one category could be compared: in_category( $single_category ).
266
 * Prior to v2.7, this function could only be used in the WordPress Loop.
267
 * As of 2.7, the function can be used anywhere if it is provided a post ID or post object.
268
 *
269
 * @since 1.2.0
270
 *
271
 * @param int|string|array $category Category ID, name or slug, or array of said.
272
 * @param int|object $post Optional. Post to check instead of the current post. (since 2.7.0)
273
 * @return bool True if the current post is in any of the given categories.
274
 */
275
function in_category( $category, $post = null ) {
276
	if ( empty( $category ) )
277
		return false;
278
279
	return has_category( $category, $post );
280
}
281
282
/**
283
 * Display the category list for the post.
284
 *
285
 * @since 0.71
286
 *
287
 * @param string $separator Optional, default is empty string. Separator for between the categories.
288
 * @param string $parents Optional. How to display the parents.
289
 * @param int $post_id Optional. Post ID to retrieve categories.
290
 */
291
function the_category( $separator = '', $parents='', $post_id = false ) {
292
	echo get_the_category_list( $separator, $parents, $post_id );
293
}
294
295
/**
296
 * Retrieve category description.
297
 *
298
 * @since 1.0.0
299
 *
300
 * @param int $category Optional. Category ID. Will use global category ID by default.
301
 * @return string Category description, available.
302
 */
303
function category_description( $category = 0 ) {
304
	return term_description( $category, 'category' );
305
}
306
307
/**
308
 * Display or retrieve the HTML dropdown list of categories.
309
 *
310
 * The 'hierarchical' argument, which is disabled by default, will override the
311
 * depth argument, unless it is true. When the argument is false, it will
312
 * display all of the categories. When it is enabled it will use the value in
313
 * the 'depth' argument.
314
 *
315
 * @since 2.1.0
316
 * @since 4.2.0 Introduced the `value_field` argument.
317
 * @since 4.6.0 Introduced the `required` argument.
318
 *
319
 * @param string|array $args {
320
 *     Optional. Array or string of arguments to generate a categories drop-down element.
321
 *
322
 *     @type string       $show_option_all   Text to display for showing all categories. Default empty.
323
 *     @type string       $show_option_none  Text to display for showing no categories. Default empty.
324
 *     @type string       $option_none_value Value to use when no category is selected. Default empty.
325
 *     @type string       $orderby           Which column to use for ordering categories. See get_terms() for a list
326
 *                                           of accepted values. Default 'id' (term_id).
327
 *     @type string       $order             Whether to order terms in ascending or descending order. Accepts 'ASC'
328
 *                                           or 'DESC'. Default 'ASC'.
329
 *     @type bool         $pad_counts        See get_terms() for an argument description. Default false.
330
 *     @type bool|int     $show_count        Whether to include post counts. Accepts 0, 1, or their bool equivalents.
331
 *                                           Default 0.
332
 *     @type bool|int     $hide_empty        Whether to hide categories that don't have any posts. Accepts 0, 1, or
333
 *                                           their bool equivalents. Default 1.
334
 *     @type int          $child_of          Term ID to retrieve child terms of. See get_terms(). Default 0.
335
 *     @type array|string $exclude           Array or comma/space-separated string of term ids to exclude.
336
 *                                           If `$include` is non-empty, `$exclude` is ignored. Default empty array.
337
 *     @type bool|int     $echo              Whether to echo or return the generated markup. Accepts 0, 1, or their
338
 *                                           bool equivalents. Default 1.
339
 *     @type bool|int     $hierarchical      Whether to traverse the taxonomy hierarchy. Accepts 0, 1, or their bool
340
 *                                           equivalents. Default 0.
341
 *     @type int          $depth             Maximum depth. Default 0.
342
 *     @type int          $tab_index         Tab index for the select element. Default 0 (no tabindex).
343
 *     @type string       $name              Value for the 'name' attribute of the select element. Default 'cat'.
344
 *     @type string       $id                Value for the 'id' attribute of the select element. Defaults to the value
345
 *                                           of `$name`.
346
 *     @type string       $class             Value for the 'class' attribute of the select element. Default 'postform'.
347
 *     @type int|string   $selected          Value of the option that should be selected. Default 0.
348
 *     @type string       $value_field       Term field that should be used to populate the 'value' attribute
349
 *                                           of the option elements. Accepts any valid term field: 'term_id', 'name',
350
 *                                           'slug', 'term_group', 'term_taxonomy_id', 'taxonomy', 'description',
351
 *                                           'parent', 'count'. Default 'term_id'.
352
 *     @type string|array $taxonomy          Name of the category or categories to retrieve. Default 'category'.
353
 *     @type bool         $hide_if_empty     True to skip generating markup if no categories are found.
354
 *                                           Default false (create select element even if no categories are found).
355
 *     @type bool         $required          Whether the `<select>` element should have the HTML5 'required' attribute.
356
 *                                           Default false.
357
 * }
358
 * @return string HTML content only if 'echo' argument is 0.
359
 */
360
function wp_dropdown_categories( $args = '' ) {
361
	$defaults = array(
362
		'show_option_all'   => '',
363
		'show_option_none'  => '',
364
		'orderby'           => 'id',
365
		'order'             => 'ASC',
366
		'show_count'        => 0,
367
		'hide_empty'        => 1,
368
		'child_of'          => 0,
369
		'exclude'           => '',
370
		'echo'              => 1,
371
		'selected'          => 0,
372
		'hierarchical'      => 0,
373
		'name'              => 'cat',
374
		'id'                => '',
375
		'class'             => 'postform',
376
		'depth'             => 0,
377
		'tab_index'         => 0,
378
		'taxonomy'          => 'category',
379
		'hide_if_empty'     => false,
380
		'option_none_value' => -1,
381
		'value_field'       => 'term_id',
382
		'required'          => false,
383
	);
384
385
	$defaults['selected'] = ( is_category() ) ? get_query_var( 'cat' ) : 0;
386
387
	// Back compat.
388 View Code Duplication
	if ( isset( $args['type'] ) && 'link' == $args['type'] ) {
389
		/* translators: 1: "type => link", 2: "taxonomy => link_category" alternative */
390
		_deprecated_argument( __FUNCTION__, '3.0.0',
391
			sprintf( __( '%1$s is deprecated. Use %2$s instead.' ),
392
				'<code>type => link</code>',
393
				'<code>taxonomy => link_category</code>'
394
			)
395
		);
396
		$args['taxonomy'] = 'link_category';
397
	}
398
399
	$r = wp_parse_args( $args, $defaults );
400
	$option_none_value = $r['option_none_value'];
401
402 View Code Duplication
	if ( ! isset( $r['pad_counts'] ) && $r['show_count'] && $r['hierarchical'] ) {
403
		$r['pad_counts'] = true;
404
	}
405
406
	$tab_index = $r['tab_index'];
407
408
	$tab_index_attribute = '';
409
	if ( (int) $tab_index > 0 ) {
410
		$tab_index_attribute = " tabindex=\"$tab_index\"";
411
	}
412
413
	// Avoid clashes with the 'name' param of get_terms().
414
	$get_terms_args = $r;
415
	unset( $get_terms_args['name'] );
416
	$categories = get_terms( $r['taxonomy'], $get_terms_args );
417
418
	$name = esc_attr( $r['name'] );
419
	$class = esc_attr( $r['class'] );
420
	$id = $r['id'] ? esc_attr( $r['id'] ) : $name;
421
	$required = $r['required'] ? 'required' : '';
422
423
	if ( ! $r['hide_if_empty'] || ! empty( $categories ) ) {
424
		$output = "<select $required name='$name' id='$id' class='$class' $tab_index_attribute>\n";
425
	} else {
426
		$output = '';
427
	}
428
	if ( empty( $categories ) && ! $r['hide_if_empty'] && ! empty( $r['show_option_none'] ) ) {
429
430
		/**
431
		 * Filters a taxonomy drop-down display element.
432
		 *
433
		 * A variety of taxonomy drop-down display elements can be modified
434
		 * just prior to display via this filter. Filterable arguments include
435
		 * 'show_option_none', 'show_option_all', and various forms of the
436
		 * term name.
437
		 *
438
		 * @since 1.2.0
439
		 *
440
		 * @see wp_dropdown_categories()
441
		 *
442
		 * @param string $element Taxonomy element to list.
443
		 */
444
		$show_option_none = apply_filters( 'list_cats', $r['show_option_none'] );
445
		$output .= "\t<option value='" . esc_attr( $option_none_value ) . "' selected='selected'>$show_option_none</option>\n";
446
	}
447
448
	if ( ! empty( $categories ) ) {
449
450
		if ( $r['show_option_all'] ) {
451
452
			/** This filter is documented in wp-includes/category-template.php */
453
			$show_option_all = apply_filters( 'list_cats', $r['show_option_all'] );
454
			$selected = ( '0' === strval($r['selected']) ) ? " selected='selected'" : '';
455
			$output .= "\t<option value='0'$selected>$show_option_all</option>\n";
456
		}
457
458
		if ( $r['show_option_none'] ) {
459
460
			/** This filter is documented in wp-includes/category-template.php */
461
			$show_option_none = apply_filters( 'list_cats', $r['show_option_none'] );
462
			$selected = selected( $option_none_value, $r['selected'], false );
463
			$output .= "\t<option value='" . esc_attr( $option_none_value ) . "'$selected>$show_option_none</option>\n";
464
		}
465
466
		if ( $r['hierarchical'] ) {
467
			$depth = $r['depth'];  // Walk the full depth.
468
		} else {
469
			$depth = -1; // Flat.
470
		}
471
		$output .= walk_category_dropdown_tree( $categories, $depth, $r );
472
	}
473
474
	if ( ! $r['hide_if_empty'] || ! empty( $categories ) ) {
475
		$output .= "</select>\n";
476
	}
477
	/**
478
	 * Filters the taxonomy drop-down output.
479
	 *
480
	 * @since 2.1.0
481
	 *
482
	 * @param string $output HTML output.
483
	 * @param array  $r      Arguments used to build the drop-down.
484
	 */
485
	$output = apply_filters( 'wp_dropdown_cats', $output, $r );
486
487
	if ( $r['echo'] ) {
488
		echo $output;
489
	}
490
	return $output;
491
}
492
493
/**
494
 * Display or retrieve the HTML list of categories.
495
 *
496
 * @since 2.1.0
497
 * @since 4.4.0 Introduced the `hide_title_if_empty` and `separator` arguments. The `current_category` argument was modified to
498
 *              optionally accept an array of values.
499
 *
500
 * @param string|array $args {
501
 *     Array of optional arguments.
502
 *
503
 *     @type int          $child_of              Term ID to retrieve child terms of. See get_terms(). Default 0.
504
 *     @type int|array    $current_category      ID of category, or array of IDs of categories, that should get the
505
 *                                               'current-cat' class. Default 0.
506
 *     @type int          $depth                 Category depth. Used for tab indentation. Default 0.
507
 *     @type bool|int     $echo                  True to echo markup, false to return it. Default 1.
508
 *     @type array|string $exclude               Array or comma/space-separated string of term IDs to exclude.
509
 *                                               If `$hierarchical` is true, descendants of `$exclude` terms will also
510
 *                                               be excluded; see `$exclude_tree`. See get_terms().
511
 *                                               Default empty string.
512
 *     @type array|string $exclude_tree          Array or comma/space-separated string of term IDs to exclude, along
513
 *                                               with their descendants. See get_terms(). Default empty string.
514
 *     @type string       $feed                  Text to use for the feed link. Default 'Feed for all posts filed
515
 *                                               under [cat name]'.
516
 *     @type string       $feed_image            URL of an image to use for the feed link. Default empty string.
517
 *     @type string       $feed_type             Feed type. Used to build feed link. See get_term_feed_link().
518
 *                                               Default empty string (default feed).
519
 *     @type bool|int     $hide_empty            Whether to hide categories that don't have any posts attached to them.
520
 *                                               Default 1.
521
 *     @type bool         $hide_title_if_empty   Whether to hide the `$title_li` element if there are no terms in
522
 *                                               the list. Default false (title will always be shown).
523
 *     @type bool         $hierarchical          Whether to include terms that have non-empty descendants.
524
 *                                               See get_terms(). Default true.
525
 *     @type string       $order                 Which direction to order categories. Accepts 'ASC' or 'DESC'.
526
 *                                               Default 'ASC'.
527
 *     @type string       $orderby               The column to use for ordering categories. Default 'ID'.
528
 *     @type string       $separator             Separator between links. Default '<br />'.
529
 *     @type bool|int     $show_count            Whether to show how many posts are in the category. Default 0.
530
 *     @type string       $show_option_all       Text to display for showing all categories. Default empty string.
531
 *     @type string       $show_option_none      Text to display for the 'no categories' option.
532
 *                                               Default 'No categories'.
533
 *     @type string       $style                 The style used to display the categories list. If 'list', categories
534
 *                                               will be output as an unordered list. If left empty or another value,
535
 *                                               categories will be output separated by `<br>` tags. Default 'list'.
536
 *     @type string       $taxonomy              Taxonomy name. Default 'category'.
537
 *     @type string       $title_li              Text to use for the list title `<li>` element. Pass an empty string
538
 *                                               to disable. Default 'Categories'.
539
 *     @type bool|int     $use_desc_for_title    Whether to use the category description as the title attribute.
540
 *                                               Default 1.
541
 * }
542
 * @return false|string HTML content only if 'echo' argument is 0.
543
 */
544
function wp_list_categories( $args = '' ) {
545
	$defaults = array(
546
		'child_of'            => 0,
547
		'current_category'    => 0,
548
		'depth'               => 0,
549
		'echo'                => 1,
550
		'exclude'             => '',
551
		'exclude_tree'        => '',
552
		'feed'                => '',
553
		'feed_image'          => '',
554
		'feed_type'           => '',
555
		'hide_empty'          => 1,
556
		'hide_title_if_empty' => false,
557
		'hierarchical'        => true,
558
		'order'               => 'ASC',
559
		'orderby'             => 'name',
560
		'separator'           => '<br />',
561
		'show_count'          => 0,
562
		'show_option_all'     => '',
563
		'show_option_none'    => __( 'No categories' ),
564
		'style'               => 'list',
565
		'taxonomy'            => 'category',
566
		'title_li'            => __( 'Categories' ),
567
		'use_desc_for_title'  => 1,
568
	);
569
570
	$r = wp_parse_args( $args, $defaults );
571
572 View Code Duplication
	if ( !isset( $r['pad_counts'] ) && $r['show_count'] && $r['hierarchical'] )
573
		$r['pad_counts'] = true;
574
575
	// Descendants of exclusions should be excluded too.
576
	if ( true == $r['hierarchical'] ) {
577
		$exclude_tree = array();
578
579
		if ( $r['exclude_tree'] ) {
580
			$exclude_tree = array_merge( $exclude_tree, wp_parse_id_list( $r['exclude_tree'] ) );
581
		}
582
583
		if ( $r['exclude'] ) {
584
			$exclude_tree = array_merge( $exclude_tree, wp_parse_id_list( $r['exclude'] ) );
585
		}
586
587
		$r['exclude_tree'] = $exclude_tree;
588
		$r['exclude'] = '';
589
	}
590
591
	if ( ! isset( $r['class'] ) )
592
		$r['class'] = ( 'category' == $r['taxonomy'] ) ? 'categories' : $r['taxonomy'];
593
594
	if ( ! taxonomy_exists( $r['taxonomy'] ) ) {
595
		return false;
596
	}
597
598
	$show_option_all = $r['show_option_all'];
599
	$show_option_none = $r['show_option_none'];
600
601
	$categories = get_categories( $r );
602
603
	$output = '';
604
	if ( $r['title_li'] && 'list' == $r['style'] && ( ! empty( $categories ) || ! $r['hide_title_if_empty'] ) ) {
605
		$output = '<li class="' . esc_attr( $r['class'] ) . '">' . $r['title_li'] . '<ul>';
606
	}
607
	if ( empty( $categories ) ) {
608
		if ( ! empty( $show_option_none ) ) {
609
			if ( 'list' == $r['style'] ) {
610
				$output .= '<li class="cat-item-none">' . $show_option_none . '</li>';
611
			} else {
612
				$output .= $show_option_none;
613
			}
614
		}
615
	} else {
616
		if ( ! empty( $show_option_all ) ) {
617
618
			$posts_page = '';
619
620
			// For taxonomies that belong only to custom post types, point to a valid archive.
621
			$taxonomy_object = get_taxonomy( $r['taxonomy'] );
622
			if ( ! in_array( 'post', $taxonomy_object->object_type ) && ! in_array( 'page', $taxonomy_object->object_type ) ) {
623
				foreach ( $taxonomy_object->object_type as $object_type ) {
624
					$_object_type = get_post_type_object( $object_type );
625
626
					// Grab the first one.
627
					if ( ! empty( $_object_type->has_archive ) ) {
628
						$posts_page = get_post_type_archive_link( $object_type );
629
						break;
630
					}
631
				}
632
			}
633
634
			// Fallback for the 'All' link is the posts page.
635
			if ( ! $posts_page ) {
636
				if ( 'page' == get_option( 'show_on_front' ) && get_option( 'page_for_posts' ) ) {
637
					$posts_page = get_permalink( get_option( 'page_for_posts' ) );
638
				} else {
639
					$posts_page = home_url( '/' );
640
				}
641
			}
642
643
			$posts_page = esc_url( $posts_page );
644
			if ( 'list' == $r['style'] ) {
645
				$output .= "<li class='cat-item-all'><a href='$posts_page'>$show_option_all</a></li>";
646
			} else {
647
				$output .= "<a href='$posts_page'>$show_option_all</a>";
648
			}
649
		}
650
651
		if ( empty( $r['current_category'] ) && ( is_category() || is_tax() || is_tag() ) ) {
652
			$current_term_object = get_queried_object();
653
			if ( $current_term_object && $r['taxonomy'] === $current_term_object->taxonomy ) {
654
				$r['current_category'] = get_queried_object_id();
655
			}
656
		}
657
658
		if ( $r['hierarchical'] ) {
659
			$depth = $r['depth'];
660
		} else {
661
			$depth = -1; // Flat.
662
		}
663
		$output .= walk_category_tree( $categories, $depth, $r );
664
	}
665
666
	if ( $r['title_li'] && 'list' == $r['style'] )
667
		$output .= '</ul></li>';
668
669
	/**
670
	 * Filters the HTML output of a taxonomy list.
671
	 *
672
	 * @since 2.1.0
673
	 *
674
	 * @param string $output HTML output.
675
	 * @param array  $args   An array of taxonomy-listing arguments.
676
	 */
677
	$html = apply_filters( 'wp_list_categories', $output, $args );
678
679
	if ( $r['echo'] ) {
680
		echo $html;
681
	} else {
682
		return $html;
683
	}
684
}
685
686
/**
687
 * Display tag cloud.
688
 *
689
 * The text size is set by the 'smallest' and 'largest' arguments, which will
690
 * use the 'unit' argument value for the CSS text size unit. The 'format'
691
 * argument can be 'flat' (default), 'list', or 'array'. The flat value for the
692
 * 'format' argument will separate tags with spaces. The list value for the
693
 * 'format' argument will format the tags in a UL HTML list. The array value for
694
 * the 'format' argument will return in PHP array type format.
695
 *
696
 * The 'orderby' argument will accept 'name' or 'count' and defaults to 'name'.
697
 * The 'order' is the direction to sort, defaults to 'ASC' and can be 'DESC'.
698
 *
699
 * The 'number' argument is how many tags to return. By default, the limit will
700
 * be to return the top 45 tags in the tag cloud list.
701
 *
702
 * The 'topic_count_text' argument is a nooped plural from _n_noop() to generate the
703
 * text for the tooltip of the tag link.
704
 *
705
 * The 'topic_count_text_callback' argument is a function, which given the count
706
 * of the posts with that tag returns a text for the tooltip of the tag link.
707
 *
708
 * The 'post_type' argument is used only when 'link' is set to 'edit'. It determines the post_type
709
 * passed to edit.php for the popular tags edit links.
710
 *
711
 * The 'exclude' and 'include' arguments are used for the get_tags() function. Only one
712
 * should be used, because only one will be used and the other ignored, if they are both set.
713
 *
714
 * @since 2.3.0
715
 *
716
 * @param array|string|null $args Optional. Override default arguments.
717
 * @return void|array Generated tag cloud, only if no failures and 'array' is set for the 'format' argument.
718
 *                    Otherwise, this function outputs the tag cloud.
719
 */
720
function wp_tag_cloud( $args = '' ) {
721
	$defaults = array(
722
		'smallest' => 8, 'largest' => 22, 'unit' => 'pt', 'number' => 45,
723
		'format' => 'flat', 'separator' => "\n", 'orderby' => 'name', 'order' => 'ASC',
724
		'exclude' => '', 'include' => '', 'link' => 'view', 'taxonomy' => 'post_tag', 'post_type' => '', 'echo' => true
725
	);
726
	$args = wp_parse_args( $args, $defaults );
727
728
	$tags = get_terms( $args['taxonomy'], array_merge( $args, array( 'orderby' => 'count', 'order' => 'DESC' ) ) ); // Always query top tags
729
730
	if ( empty( $tags ) || is_wp_error( $tags ) )
731
		return;
732
733
	foreach ( $tags as $key => $tag ) {
734
		if ( 'edit' == $args['link'] )
735
			$link = get_edit_term_link( $tag->term_id, $tag->taxonomy, $args['post_type'] );
736
		else
737
			$link = get_term_link( intval($tag->term_id), $tag->taxonomy );
738
		if ( is_wp_error( $link ) )
739
			return;
740
741
		$tags[ $key ]->link = $link;
742
		$tags[ $key ]->id = $tag->term_id;
743
	}
744
745
	$return = wp_generate_tag_cloud( $tags, $args ); // Here's where those top tags get sorted according to $args
746
747
	/**
748
	 * Filters the tag cloud output.
749
	 *
750
	 * @since 2.3.0
751
	 *
752
	 * @param string $return HTML output of the tag cloud.
753
	 * @param array  $args   An array of tag cloud arguments.
754
	 */
755
	$return = apply_filters( 'wp_tag_cloud', $return, $args );
756
757
	if ( 'array' == $args['format'] || empty($args['echo']) )
758
		return $return;
759
760
	echo $return;
761
}
762
763
/**
764
 * Default topic count scaling for tag links
765
 *
766
 * @param int $count number of posts with that tag
767
 * @return int scaled count
768
 */
769
function default_topic_count_scale( $count ) {
770
	return round(log10($count + 1) * 100);
771
}
772
773
/**
774
 * Generates a tag cloud (heatmap) from provided data.
775
 *
776
 * @todo Complete functionality.
777
 * @since 2.3.0
778
 *
779
 * @param array $tags List of tags.
780
 * @param string|array $args {
781
 *     Optional. Array of string of arguments for generating a tag cloud.
782
 *
783
 *     @type int      $smallest                   Smallest font size used to display tags. Paired
784
 *                                                with the value of `$unit`, to determine CSS text
785
 *                                                size unit. Default 8 (pt).
786
 *     @type int      $largest                    Largest font size used to display tags. Paired
787
 *                                                with the value of `$unit`, to determine CSS text
788
 *                                                size unit. Default 22 (pt).
789
 *     @type string   $unit                       CSS text size unit to use with the `$smallest`
790
 *                                                and `$largest` values. Accepts any valid CSS text
791
 *                                                size unit. Default 'pt'.
792
 *     @type int      $number                     The number of tags to return. Accepts any
793
 *                                                positive integer or zero to return all.
794
 *                                                Default 0.
795
 *     @type string   $format                     Format to display the tag cloud in. Accepts 'flat'
796
 *                                                (tags separated with spaces), 'list' (tags displayed
797
 *                                                in an unordered list), or 'array' (returns an array).
798
 *                                                Default 'flat'.
799
 *     @type string   $separator                  HTML or text to separate the tags. Default "\n" (newline).
800
 *     @type string   $orderby                    Value to order tags by. Accepts 'name' or 'count'.
801
 *                                                Default 'name'. The {@see 'tag_cloud_sort'} filter
802
 *                                                can also affect how tags are sorted.
803
 *     @type string   $order                      How to order the tags. Accepts 'ASC' (ascending),
804
 *                                                'DESC' (descending), or 'RAND' (random). Default 'ASC'.
805
 *     @type int|bool $filter                     Whether to enable filtering of the final output
806
 *                                                via {@see 'wp_generate_tag_cloud'}. Default 1|true.
807
 *     @type string   $topic_count_text           Nooped plural text from _n_noop() to supply to
808
 *                                                tag tooltips. Default null.
809
 *     @type callable $topic_count_text_callback  Callback used to generate nooped plural text for
810
 *                                                tag tooltips based on the count. Default null.
811
 *     @type callable $topic_count_scale_callback Callback used to determine the tag count scaling
812
 *                                                value. Default default_topic_count_scale().
813
 * }
814
 * @return string|array Tag cloud as a string or an array, depending on 'format' argument.
815
 */
816
function wp_generate_tag_cloud( $tags, $args = '' ) {
817
	$defaults = array(
818
		'smallest' => 8, 'largest' => 22, 'unit' => 'pt', 'number' => 0,
819
		'format' => 'flat', 'separator' => "\n", 'orderby' => 'name', 'order' => 'ASC',
820
		'topic_count_text' => null, 'topic_count_text_callback' => null,
821
		'topic_count_scale_callback' => 'default_topic_count_scale', 'filter' => 1,
822
	);
823
824
	$args = wp_parse_args( $args, $defaults );
825
826
	$return = ( 'array' === $args['format'] ) ? array() : '';
827
828
	if ( empty( $tags ) ) {
829
		return $return;
830
	}
831
832
	// Juggle topic count tooltips:
833
	if ( isset( $args['topic_count_text'] ) ) {
834
		// First look for nooped plural support via topic_count_text.
835
		$translate_nooped_plural = $args['topic_count_text'];
836
	} elseif ( ! empty( $args['topic_count_text_callback'] ) ) {
837
		// Look for the alternative callback style. Ignore the previous default.
838
		if ( $args['topic_count_text_callback'] === 'default_topic_count_text' ) {
839
			$translate_nooped_plural = _n_noop( '%s topic', '%s topics' );
840
		} else {
841
			$translate_nooped_plural = false;
842
		}
843
	} elseif ( isset( $args['single_text'] ) && isset( $args['multiple_text'] ) ) {
844
		// If no callback exists, look for the old-style single_text and multiple_text arguments.
845
		$translate_nooped_plural = _n_noop( $args['single_text'], $args['multiple_text'] );
846
	} else {
847
		// This is the default for when no callback, plural, or argument is passed in.
848
		$translate_nooped_plural = _n_noop( '%s topic', '%s topics' );
849
	}
850
851
	/**
852
	 * Filters how the items in a tag cloud are sorted.
853
	 *
854
	 * @since 2.8.0
855
	 *
856
	 * @param array $tags Ordered array of terms.
857
	 * @param array $args An array of tag cloud arguments.
858
	 */
859
	$tags_sorted = apply_filters( 'tag_cloud_sort', $tags, $args );
860
	if ( empty( $tags_sorted ) ) {
861
		return $return;
862
	}
863
864
	if ( $tags_sorted !== $tags ) {
865
		$tags = $tags_sorted;
866
		unset( $tags_sorted );
867
	} else {
868
		if ( 'RAND' === $args['order'] ) {
869
			shuffle( $tags );
870
		} else {
871
			// SQL cannot save you; this is a second (potentially different) sort on a subset of data.
872
			if ( 'name' === $args['orderby'] ) {
873
				uasort( $tags, '_wp_object_name_sort_cb' );
874
			} else {
875
				uasort( $tags, '_wp_object_count_sort_cb' );
876
			}
877
878
			if ( 'DESC' === $args['order'] ) {
879
				$tags = array_reverse( $tags, true );
880
			}
881
		}
882
	}
883
884
	if ( $args['number'] > 0 )
885
		$tags = array_slice( $tags, 0, $args['number'] );
886
887
	$counts = array();
888
	$real_counts = array(); // For the alt tag
889
	foreach ( (array) $tags as $key => $tag ) {
890
		$real_counts[ $key ] = $tag->count;
891
		$counts[ $key ] = call_user_func( $args['topic_count_scale_callback'], $tag->count );
892
	}
893
894
	$min_count = min( $counts );
895
	$spread = max( $counts ) - $min_count;
896
	if ( $spread <= 0 )
897
		$spread = 1;
898
	$font_spread = $args['largest'] - $args['smallest'];
899
	if ( $font_spread < 0 )
900
		$font_spread = 1;
901
	$font_step = $font_spread / $spread;
902
903
	// Assemble the data that will be used to generate the tag cloud markup.
904
	$tags_data = array();
905
	foreach ( $tags as $key => $tag ) {
906
		$tag_id = isset( $tag->id ) ? $tag->id : $key;
907
908
		$count = $counts[ $key ];
909
		$real_count = $real_counts[ $key ];
910
911
		if ( $translate_nooped_plural ) {
912
			$title = sprintf( translate_nooped_plural( $translate_nooped_plural, $real_count ), number_format_i18n( $real_count ) );
913
		} else {
914
			$title = call_user_func( $args['topic_count_text_callback'], $real_count, $tag, $args );
915
		}
916
917
		$tags_data[] = array(
918
			'id'         => $tag_id,
919
			'url'        => '#' != $tag->link ? $tag->link : '#',
920
			'name'	     => $tag->name,
921
			'title'      => $title,
922
			'slug'       => $tag->slug,
923
			'real_count' => $real_count,
924
			'class'	     => 'tag-link-' . $tag_id,
925
			'font_size'  => $args['smallest'] + ( $count - $min_count ) * $font_step,
926
		);
927
	}
928
929
	/**
930
	 * Filters the data used to generate the tag cloud.
931
	 *
932
	 * @since 4.3.0
933
	 *
934
	 * @param array $tags_data An array of term data for term used to generate the tag cloud.
935
	 */
936
	$tags_data = apply_filters( 'wp_generate_tag_cloud_data', $tags_data );
937
938
	$a = array();
939
940
	// generate the output links array
941
	foreach ( $tags_data as $key => $tag_data ) {
942
		$class = $tag_data['class'] . ' tag-link-position-' . ( $key + 1 );
943
		$a[] = "<a href='" . esc_url( $tag_data['url'] ) . "' class='" . esc_attr( $class ) . "' title='" . esc_attr( $tag_data['title'] ) . "' style='font-size: " . esc_attr( str_replace( ',', '.', $tag_data['font_size'] ) . $args['unit'] ) . ";'>" . esc_html( $tag_data['name'] ) . "</a>";
944
	}
945
946
	switch ( $args['format'] ) {
947
		case 'array' :
948
			$return =& $a;
949
			break;
950
		case 'list' :
951
			$return = "<ul class='wp-tag-cloud'>\n\t<li>";
952
			$return .= join( "</li>\n\t<li>", $a );
953
			$return .= "</li>\n</ul>\n";
954
			break;
955
		default :
956
			$return = join( $args['separator'], $a );
957
			break;
958
	}
959
960
	if ( $args['filter'] ) {
961
		/**
962
		 * Filters the generated output of a tag cloud.
963
		 *
964
		 * The filter is only evaluated if a true value is passed
965
		 * to the $filter argument in wp_generate_tag_cloud().
966
		 *
967
		 * @since 2.3.0
968
		 *
969
		 * @see wp_generate_tag_cloud()
970
		 *
971
		 * @param array|string $return String containing the generated HTML tag cloud output
972
		 *                             or an array of tag links if the 'format' argument
973
		 *                             equals 'array'.
974
		 * @param array        $tags   An array of terms used in the tag cloud.
975
		 * @param array        $args   An array of wp_generate_tag_cloud() arguments.
976
		 */
977
		return apply_filters( 'wp_generate_tag_cloud', $return, $tags, $args );
978
	}
979
980
	else
981
		return $return;
982
}
983
984
/**
985
 * Serves as a callback for comparing objects based on name.
986
 *
987
 * Used with `uasort()`.
988
 *
989
 * @since 3.1.0
990
 * @access private
991
 *
992
 * @param object $a The first object to compare.
993
 * @param object $b The second object to compare.
994
 * @return int Negative number if `$a->name` is less than `$b->name`, zero if they are equal,
995
 *             or greater than zero if `$a->name` is greater than `$b->name`.
996
 */
997
function _wp_object_name_sort_cb( $a, $b ) {
998
	return strnatcasecmp( $a->name, $b->name );
999
}
1000
1001
/**
1002
 * Serves as a callback for comparing objects based on count.
1003
 *
1004
 * Used with `uasort()`.
1005
 *
1006
 * @since 3.1.0
1007
 * @access private
1008
 *
1009
 * @param object $a The first object to compare.
1010
 * @param object $b The second object to compare.
1011
 * @return bool Whether the count value for `$a` is greater than the count value for `$b`.
1012
 */
1013
function _wp_object_count_sort_cb( $a, $b ) {
1014
	return ( $a->count > $b->count );
1015
}
1016
1017
//
1018
// Helper functions
1019
//
1020
1021
/**
1022
 * Retrieve HTML list content for category list.
1023
 *
1024
 * @uses Walker_Category to create HTML list content.
1025
 * @since 2.1.0
1026
 * @see Walker_Category::walk() for parameters and return description.
1027
 * @return string
1028
 */
1029 View Code Duplication
function walk_category_tree() {
1030
	$args = func_get_args();
1031
	// the user's options are the third parameter
1032
	if ( empty( $args[2]['walker'] ) || ! ( $args[2]['walker'] instanceof Walker ) ) {
1033
		$walker = new Walker_Category;
1034
	} else {
1035
		$walker = $args[2]['walker'];
1036
	}
1037
	return call_user_func_array( array( $walker, 'walk' ), $args );
1038
}
1039
1040
/**
1041
 * Retrieve HTML dropdown (select) content for category list.
1042
 *
1043
 * @uses Walker_CategoryDropdown to create HTML dropdown content.
1044
 * @since 2.1.0
1045
 * @see Walker_CategoryDropdown::walk() for parameters and return description.
1046
 * @return string
1047
 */
1048 View Code Duplication
function walk_category_dropdown_tree() {
1049
	$args = func_get_args();
1050
	// the user's options are the third parameter
1051
	if ( empty( $args[2]['walker'] ) || ! ( $args[2]['walker'] instanceof Walker ) ) {
1052
		$walker = new Walker_CategoryDropdown;
1053
	} else {
1054
		$walker = $args[2]['walker'];
1055
	}
1056
	return call_user_func_array( array( $walker, 'walk' ), $args );
1057
}
1058
1059
//
1060
// Tags
1061
//
1062
1063
/**
1064
 * Retrieve the link to the tag.
1065
 *
1066
 * @since 2.3.0
1067
 * @see get_term_link()
1068
 *
1069
 * @param int|object $tag Tag ID or object.
1070
 * @return string Link on success, empty string if tag does not exist.
1071
 */
1072 View Code Duplication
function get_tag_link( $tag ) {
1073
	if ( ! is_object( $tag ) )
1074
		$tag = (int) $tag;
1075
1076
	$tag = get_term_link( $tag, 'post_tag' );
1077
1078
	if ( is_wp_error( $tag ) )
1079
		return '';
1080
1081
	return $tag;
1082
}
1083
1084
/**
1085
 * Retrieve the tags for a post.
1086
 *
1087
 * @since 2.3.0
1088
 *
1089
 * @param int $id Post ID.
1090
 * @return array|false|WP_Error Array of tag objects on success, false on failure.
1091
 */
1092
function get_the_tags( $id = 0 ) {
1093
1094
	/**
1095
	 * Filters the array of tags for the given post.
1096
	 *
1097
	 * @since 2.3.0
1098
	 *
1099
	 * @see get_the_terms()
1100
	 *
1101
	 * @param array $terms An array of tags for the given post.
1102
	 */
1103
	return apply_filters( 'get_the_tags', get_the_terms( $id, 'post_tag' ) );
1104
}
1105
1106
/**
1107
 * Retrieve the tags for a post formatted as a string.
1108
 *
1109
 * @since 2.3.0
1110
 *
1111
 * @param string $before Optional. Before tags.
1112
 * @param string $sep Optional. Between tags.
1113
 * @param string $after Optional. After tags.
1114
 * @param int $id Optional. Post ID. Defaults to the current post.
1115
 * @return string|false|WP_Error A list of tags on success, false if there are no terms, WP_Error on failure.
1116
 */
1117
function get_the_tag_list( $before = '', $sep = '', $after = '', $id = 0 ) {
1118
1119
	/**
1120
	 * Filters the tags list for a given post.
1121
	 *
1122
	 * @since 2.3.0
1123
	 *
1124
	 * @param string $tag_list List of tags.
1125
	 * @param string $before   String to use before tags.
1126
	 * @param string $sep      String to use between the tags.
1127
	 * @param string $after    String to use after tags.
1128
	 * @param int    $id       Post ID.
1129
	 */
1130
	return apply_filters( 'the_tags', get_the_term_list( $id, 'post_tag', $before, $sep, $after ), $before, $sep, $after, $id );
1131
}
1132
1133
/**
1134
 * Retrieve the tags for a post.
1135
 *
1136
 * @since 2.3.0
1137
 *
1138
 * @param string $before Optional. Before list.
1139
 * @param string $sep Optional. Separate items using this.
1140
 * @param string $after Optional. After list.
1141
 */
1142
function the_tags( $before = null, $sep = ', ', $after = '' ) {
1143
	if ( null === $before )
1144
		$before = __('Tags: ');
1145
	echo get_the_tag_list($before, $sep, $after);
1146
}
1147
1148
/**
1149
 * Retrieve tag description.
1150
 *
1151
 * @since 2.8.0
1152
 *
1153
 * @param int $tag Optional. Tag ID. Will use global tag ID by default.
1154
 * @return string Tag description, available.
1155
 */
1156
function tag_description( $tag = 0 ) {
1157
	return term_description( $tag );
1158
}
1159
1160
/**
1161
 * Retrieve term description.
1162
 *
1163
 * @since 2.8.0
1164
 *
1165
 * @param int $term Optional. Term ID. Will use global term ID by default.
1166
 * @param string $taxonomy Optional taxonomy name. Defaults to 'post_tag'.
1167
 * @return string Term description, available.
1168
 */
1169
function term_description( $term = 0, $taxonomy = 'post_tag' ) {
1170
	if ( ! $term && ( is_tax() || is_tag() || is_category() ) ) {
1171
		$term = get_queried_object();
1172
		if ( $term ) {
1173
			$taxonomy = $term->taxonomy;
1174
			$term = $term->term_id;
1175
		}
1176
	}
1177
	$description = get_term_field( 'description', $term, $taxonomy );
1178
	return is_wp_error( $description ) ? '' : $description;
1179
}
1180
1181
/**
1182
 * Retrieve the terms of the taxonomy that are attached to the post.
1183
 *
1184
 * @since 2.5.0
1185
 *
1186
 * @param int|object $post Post ID or object.
1187
 * @param string $taxonomy Taxonomy name.
1188
 * @return array|false|WP_Error Array of WP_Term objects on success, false if there are no terms
1189
 *                              or the post does not exist, WP_Error on failure.
1190
 */
1191
function get_the_terms( $post, $taxonomy ) {
1192
	if ( ! $post = get_post( $post ) )
1193
		return false;
1194
1195
	$terms = get_object_term_cache( $post->ID, $taxonomy );
1196
	if ( false === $terms ) {
1197
		$terms = wp_get_object_terms( $post->ID, $taxonomy );
1198 View Code Duplication
		if ( ! is_wp_error( $terms ) ) {
1199
			$term_ids = wp_list_pluck( $terms, 'term_id' );
1200
			wp_cache_add( $post->ID, $term_ids, $taxonomy . '_relationships' );
1201
		}
1202
	}
1203
1204
	/**
1205
	 * Filters the list of terms attached to the given post.
1206
	 *
1207
	 * @since 3.1.0
1208
	 *
1209
	 * @param array|WP_Error $terms    List of attached terms, or WP_Error on failure.
1210
	 * @param int            $post_id  Post ID.
1211
	 * @param string         $taxonomy Name of the taxonomy.
1212
	 */
1213
	$terms = apply_filters( 'get_the_terms', $terms, $post->ID, $taxonomy );
1214
1215
	if ( empty( $terms ) )
1216
		return false;
1217
1218
	return $terms;
1219
}
1220
1221
/**
1222
 * Retrieve a post's terms as a list with specified format.
1223
 *
1224
 * @since 2.5.0
1225
 *
1226
 * @param int $id Post ID.
1227
 * @param string $taxonomy Taxonomy name.
1228
 * @param string $before Optional. Before list.
1229
 * @param string $sep Optional. Separate items using this.
1230
 * @param string $after Optional. After list.
1231
 * @return string|false|WP_Error A list of terms on success, false if there are no terms, WP_Error on failure.
1232
 */
1233
function get_the_term_list( $id, $taxonomy, $before = '', $sep = '', $after = '' ) {
1234
	$terms = get_the_terms( $id, $taxonomy );
1235
1236
	if ( is_wp_error( $terms ) )
1237
		return $terms;
1238
1239
	if ( empty( $terms ) )
1240
		return false;
1241
1242
	$links = array();
1243
1244
	foreach ( $terms as $term ) {
1245
		$link = get_term_link( $term, $taxonomy );
1246
		if ( is_wp_error( $link ) ) {
1247
			return $link;
1248
		}
1249
		$links[] = '<a href="' . esc_url( $link ) . '" rel="tag">' . $term->name . '</a>';
1250
	}
1251
1252
	/**
1253
	 * Filters the term links for a given taxonomy.
1254
	 *
1255
	 * The dynamic portion of the filter name, `$taxonomy`, refers
1256
	 * to the taxonomy slug.
1257
	 *
1258
	 * @since 2.5.0
1259
	 *
1260
	 * @param array $links An array of term links.
1261
	 */
1262
	$term_links = apply_filters( "term_links-{$taxonomy}", $links );
1263
1264
	return $before . join( $sep, $term_links ) . $after;
1265
}
1266
1267
/**
1268
 * Display the terms in a list.
1269
 *
1270
 * @since 2.5.0
1271
 *
1272
 * @param int $id Post ID.
1273
 * @param string $taxonomy Taxonomy name.
1274
 * @param string $before Optional. Before list.
1275
 * @param string $sep Optional. Separate items using this.
1276
 * @param string $after Optional. After list.
1277
 * @return false|void False on WordPress error.
1278
 */
1279
function the_terms( $id, $taxonomy, $before = '', $sep = ', ', $after = '' ) {
1280
	$term_list = get_the_term_list( $id, $taxonomy, $before, $sep, $after );
1281
1282
	if ( is_wp_error( $term_list ) )
1283
		return false;
1284
1285
	/**
1286
	 * Filters the list of terms to display.
1287
	 *
1288
	 * @since 2.9.0
1289
	 *
1290
	 * @param array  $term_list List of terms to display.
1291
	 * @param string $taxonomy  The taxonomy name.
1292
	 * @param string $before    String to use before the terms.
1293
	 * @param string $sep       String to use between the terms.
1294
	 * @param string $after     String to use after the terms.
1295
	 */
1296
	echo apply_filters( 'the_terms', $term_list, $taxonomy, $before, $sep, $after );
1297
}
1298
1299
/**
1300
 * Check if the current post has any of given category.
1301
 *
1302
 * @since 3.1.0
1303
 *
1304
 * @param string|int|array $category Optional. The category name/term_id/slug or array of them to check for.
1305
 * @param int|object $post Optional. Post to check instead of the current post.
1306
 * @return bool True if the current post has any of the given categories (or any category, if no category specified).
1307
 */
1308
function has_category( $category = '', $post = null ) {
1309
	return has_term( $category, 'category', $post );
1310
}
1311
1312
/**
1313
 * Check if the current post has any of given tags.
1314
 *
1315
 * The given tags are checked against the post's tags' term_ids, names and slugs.
1316
 * Tags given as integers will only be checked against the post's tags' term_ids.
1317
 * If no tags are given, determines if post has any tags.
1318
 *
1319
 * 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)
1320
 * Prior to v2.7, this function could only be used in the WordPress Loop.
1321
 * As of 2.7, the function can be used anywhere if it is provided a post ID or post object.
1322
 *
1323
 * @since 2.6.0
1324
 *
1325
 * @param string|int|array $tag Optional. The tag name/term_id/slug or array of them to check for.
1326
 * @param int|object $post Optional. Post to check instead of the current post. (since 2.7.0)
1327
 * @return bool True if the current post has any of the given tags (or any tag, if no tag specified).
1328
 */
1329
function has_tag( $tag = '', $post = null ) {
1330
	return has_term( $tag, 'post_tag', $post );
1331
}
1332
1333
/**
1334
 * Check if the current post has any of given terms.
1335
 *
1336
 * The given terms are checked against the post's terms' term_ids, names and slugs.
1337
 * Terms given as integers will only be checked against the post's terms' term_ids.
1338
 * If no terms are given, determines if post has any terms.
1339
 *
1340
 * @since 3.1.0
1341
 *
1342
 * @param string|int|array $term Optional. The term name/term_id/slug or array of them to check for.
1343
 * @param string $taxonomy Taxonomy name
1344
 * @param int|object $post Optional. Post to check instead of the current post.
1345
 * @return bool True if the current post has any of the given tags (or any tag, if no tag specified).
1346
 */
1347
function has_term( $term = '', $taxonomy = '', $post = null ) {
1348
	$post = get_post($post);
1349
1350
	if ( !$post )
1351
		return false;
1352
1353
	$r = is_object_in_term( $post->ID, $taxonomy, $term );
1354
	if ( is_wp_error( $r ) )
1355
		return false;
1356
1357
	return $r;
1358
}
1359