home *** CD-ROM | disk | FTP | other *** search
/ HTML Examples / WP.iso / wordpress / wp-includes / category-template.php < prev    next >
Encoding:
PHP Script  |  2017-12-21  |  50.1 KB  |  1,416 lines

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