/**
  * Retrieve category parents with separator.
  *
  * NOTE: This is the Connections equivalent of @see get_category_parents() in WordPress core ../wp-includes/category-template.php
  *
  * @access public
  * @since  8.5.18
  * @static
  *
  * @param int    $id        Category ID.
  * @param array  $atts      The attributes array. {
  *
  *     @type bool   $link       Whether to format as link or as a string.
  *                              Default: FALSE
  *     @type string $separator  How to separate categories.
  *                              Default: '/'
  *     @type bool   $nicename   Whether to use nice name for display.
  *                              Default: FALSE
  *     @type array  $visited    Already linked to categories to prevent duplicates.
  *                              Default: array()
  *     @type bool   $force_home Default: FALSE
  *     @type int    $home_id    Default: The page set as the directory home page.
  * }
  *
  * @return string|WP_Error A list of category parents on success, WP_Error on failure.
  */
 public static function getCategoryParents($id, $atts = array())
 {
     $defaults = array('link' => FALSE, 'separator' => '/', 'nicename' => FALSE, 'visited' => array(), 'force_home' => FALSE, 'home_id' => cnSettingsAPI::get('connections', 'connections_home_page', 'page_id'));
     $atts = cnSanitize::args($atts, $defaults);
     $chain = '';
     $parent = cnTerm::get($id, 'category');
     if (is_wp_error($parent)) {
         return $parent;
     }
     if ($atts['nicename']) {
         $name = $parent->slug;
     } else {
         $name = $parent->name;
     }
     if ($parent->parent && $parent->parent != $parent->term_id && !in_array($parent->parent, $atts['visited'])) {
         $atts['visited'][] = $parent->parent;
         $chain .= self::getCategoryParents($parent->parent, $atts);
     }
     if ($atts['link']) {
         $chain .= '<a href="' . esc_url(cnTerm::permalink($parent->term_id, 'category', $atts)) . '">' . $name . '</a>' . $atts['separator'];
     } else {
         $chain .= $name . esc_html($atts['separator']);
     }
     return $chain;
 }
 /**
  * Render the term name column.
  *
  * @access public
  * @since  8.2
  *
  * @uses   cnFormObjects::tokenURL()
  * @uses   apply_filters()
  * @uses   esc_attr()
  * @uses   cnTerm::permalink()
  * @uses   WP_List_Table::row_actions()
  *
  * @param  object $term
  *
  * @return string
  */
 public function column_name($term)
 {
     $form = new cnFormObjects();
     $actions = array();
     $out = '';
     $pad = str_repeat('&#8212; ', max(0, $this->level));
     /**
      * Filter display of the term name in the terms list table.
      *
      * The default output may include padding due to the term's
      * current level in the term hierarchy.
      *
      * @since 8.2
      *
      * @see   WP_Terms_List_Table::column_name()
      *
      * @param string $pad_tag_name The term name, padded if not top-level.
      * @param object $term         Term object.
      */
     $name = apply_filters('cn_term_name', $pad . ' ' . $term->name, $term);
     if ($term->term_id != $this->default_term) {
         $editURL = $form->tokenURL('admin.php?page=connections_categories&cn-action=edit_category&id=' . $term->term_id, 'category_edit_' . $term->term_id);
         $deleteURL = $form->tokenURL('admin.php?cn-action=delete_category&id=' . $term->term_id, 'category_delete_' . $term->term_id);
         $out .= '<strong><a class="row-title" href="' . $editURL . '" title="' . esc_attr(sprintf(__('Edit &#8220;%s&#8221;', 'connections'), $name)) . '">' . $name . '</a></strong><br />';
         $actions['edit'] = '<a href="' . $editURL . '">' . __('Edit', 'connections') . '</a>';
         $actions['delete'] = "<a class='delete-tag' href='" . $deleteURL . "'>" . __('Delete', 'connections') . "</a>";
         $actions['view'] = '<a href="' . cnTerm::permalink($term) . '">' . __('View', 'connections') . '</a>';
     } else {
         $out .= '<strong>' . $name . '</strong><br>';
     }
     /**
      * Filter the action links displayed for each term in the terms list table.
      *
      * The dynamic portion of the hook name, `$taxonomy`, refers to the taxonomy slug.
      *
      * @since 8.2
      *
      * @param array  $actions An array of action links to be displayed. Default
      *                        'Edit', 'Delete', and 'View'.
      * @param object $term    Term object.
      */
     $actions = apply_filters("cn_{$this->taxonomy}_row_actions", $actions, $term);
     $out .= $this->row_actions($actions);
     return $out;
 }
 /**
  * Start the element output.
  *
  * @see   Walker::start_el()
  *
  * @since 8.1.6
  *
  * @uses   esc_attr()
  * @uses   number_format_i18n()
  * @uses   cnTerm::get()
  *
  * @param string $output Passed by reference. Used to append additional content.
  * @param object $term   Term object.
  * @param int    $depth  Depth of category in reference to parents. Default 0.
  * @param array  $args   An array of arguments. @see CN_Walker_Term_List::render()
  * @param int    $id     ID of the current term.
  */
 public function start_el(&$output, $term, $depth = 0, $args = array(), $id = 0)
 {
     $indent = str_repeat("\t", $depth);
     $count = $args['show_count'] ? '&nbsp;(' . number_format_i18n($term->count) . ')' : '';
     $url = cnTerm::permalink($term, 'category');
     $link = sprintf('<a href="%1$s" title="%2$s">%3$s</a>', $url, esc_attr($term->name), esc_html($term->name . $count));
     $class = 'cat-item cat-item-' . $term->term_id . ' cn-cat-parent';
     if (!empty($args['current_category'])) {
         if (is_numeric($args['current_category'])) {
             $_current_category = cnTerm::get($args['current_category'], $term->taxonomy);
         } else {
             $_current_category = new stdClass();
             $_current_category->parent = 0;
         }
         if ($term->slug == $args['current_category']) {
             $class .= ' current-cat';
         } elseif ($term->term_id == $args['current_category']) {
             $class .= ' current-cat';
         } elseif ($term->term_id == $_current_category->parent) {
             $class .= ' current-cat-parent';
         }
     }
     $output .= "{$indent}<li" . ' class="' . $class . '"' . ">{$link}</li>" . PHP_EOL;
 }
 /**
  * Start the element output.
  *
  * @see   Walker::start_el()
  *
  * @since 8.1.6
  *
  * @uses   esc_attr()
  * @uses   number_format_i18n()
  * @uses   cnTerm::get()
  *
  * @param string $output Passed by reference. Used to append additional content.
  * @param object $term   Term object.
  * @param int    $depth  Depth of category in reference to parents. Default 0.
  * @param array  $args   An array of arguments. @see CN_Walker_Term_List::render()
  * @param int    $id     ID of the current term.
  */
 public function start_el(&$output, $term, $depth = 0, $args = array(), $id = 0)
 {
     $indent = str_repeat("\t", $depth);
     $count = $args['show_count'] ? '<span class="cn-cat-count">&nbsp;(' . esc_html(number_format_i18n($term->count)) . ')</span>' : '';
     $url = cnTerm::permalink($term, 'category', $args);
     $html = sprintf('<a href="%1$s" title="%2$s">%3$s</a>', $url, esc_attr($term->name), esc_html($term->name) . $count);
     /**
      * Allows extensions to alter the HTML of term list item.
      *
      * @since 8.5.18
      *
      * @param string        $html  The HTML.
      * @param cnTerm_Object $term  The current term.
      * @param int           $depth Depth of category. Used for tab indentation.
      * @param array         $args  The method attributes.
      */
     $html = apply_filters('cn_term_list_item', $html, $term, $depth, $args);
     $class = array('cat-item', 'cat-item-' . $term->term_id, 'cn-cat-parent');
     $termChildren = cnTerm::getTaxonomyTerms($term->taxonomy, array('parent' => $term->term_id, 'hide_empty' => FALSE, 'fields' => 'count'));
     if (!empty($termChildren)) {
         $class[] = 'cn-cat-has-children';
     }
     if (!empty($args['current_category'])) {
         if (is_numeric($args['current_category'])) {
             $_current_category = cnTerm::get($args['current_category'], $term->taxonomy);
             // cnTerm::get() can return NULL || an instance of WP_Error, so, lets check for that.
             if (is_null($_current_category) || is_wp_error($_current_category)) {
                 $_current_category = new stdClass();
                 $_current_category->parent = 0;
             }
         } else {
             $_current_category = new stdClass();
             $_current_category->parent = 0;
         }
         if ($term->slug == $args['current_category']) {
             $class[] = ' current-cat';
         } elseif ($term->term_id == $args['current_category']) {
             $class[] = ' current-cat';
         } elseif ($term->term_id == $_current_category->parent) {
             $class[] = ' current-cat-parent';
         }
     }
     /**
      * Allows extensions to add/remove class names to the current term list item.
      *
      * @since 8.5.18
      *
      * @param array         $class The array of class names.
      * @param cnTerm_Object $term  The current term.
      * @param int           $depth Depth of category. Used for tab indentation.
      * @param array         $args  The method attributes.
      */
     $class = apply_filters('cn_term_list_item_class', $class, $term, $depth, $args);
     $class = cnSanitize::htmlClass($class);
     $output .= "{$indent}<li" . ' class="' . cnFunction::escAttributeDeep($class) . '"' . ">{$html}";
     // Do not add EOL here, it'll add unwanted whitespace if terms are inline.
 }
 /**
  * Displays the category list in a HTML list or custom format.
  *
  * NOTE: This is the Connections equivalent of @see get_the_category_list() in WordPress core ../wp-includes/category-template.php
  *
  * @access public
  * @since  unknown
  *
  * @param array $atts {
  * Optional. An array of arguments.
  *
  *     @type string $container_tag    The HTML tag to be used for the container element.
  *                                    Default: div
  *     @type string $label_tag        The HTML tag to be used for the category label element.
  *                                    Default: span
  *     @type string $item_tag         The HTML tag to be used for the category element.
  *                                    Default: span
  *     @type string $type             The display type to be used to display the categories.
  *                                    Accepts: block|list
  *                                    Default: block
  *     @type string $list             If the $type is list, which type?
  *                                    Accepts: ordered|unordered
  *                                    Default: unordered
  *     @type string $label            The label to be displayed before the categories.
  *                                    Default: Categories:
  *     @type string $separator        The category separator used when separating categories when $type == list
  *                                    Default: ', '
  *     @type string $parent_separator The separator to be used when displaying the category's hierarchy.
  *                                    Default: ' &raquo; '
  *     @type string $before           String content to display before the categories.
  *     @type string $after            String content to display after the categories.
  *     @type bool   $link             Whether or not render the categories as permalinks.
  *                                    Default: false
  *     @type bool   $parents          Whether or not to display the category hierarchy.
  *                                    Default: false
  *     @type bool   $return           Whether or not to echo or return the HTML.
  *                                    Default: false
  * }
  *
  * @return string
  */
 public function getCategoryBlock($atts = array())
 {
     global $wp_rewrite;
     $defaults = array('container_tag' => 'div', 'label_tag' => 'span', 'item_tag' => 'span', 'type' => 'block', 'list' => 'unordered', 'label' => __('Categories:', 'connections') . ' ', 'separator' => ', ', 'parent_separator' => ' &raquo; ', 'before' => '', 'after' => '', 'link' => FALSE, 'parents' => FALSE, 'return' => FALSE);
     /**
      * All extensions to filter the method default and supplied args.
      *
      * @since 8.5.18
      */
     $atts = cnSanitize::args(apply_filters('cn_output_atts_category', $atts), apply_filters('cn_output_default_atts_category', $defaults));
     $categories = $this->getCategory();
     $count = count($categories);
     $html = '';
     $label = '';
     $items = array();
     if (empty($categories)) {
         return $html;
     }
     if ('list' == $atts['type']) {
         $atts['item_tag'] = 'li';
     }
     if (0 < strlen($atts['label'])) {
         $label = sprintf('<%1$s class="cn_category_label">%2$s</%1$s> ', $atts['label_tag'], esc_html($atts['label']));
     }
     $i = 1;
     foreach ($categories as $category) {
         $text = '';
         if ($atts['parents']) {
             // If the term is a root parent, skip.
             if (0 !== $category->parent) {
                 $text .= cnTemplatePart::getCategoryParents($category->parent, array('link' => $atts['link'], 'separator' => $atts['parent_separator'], 'force_home' => $this->directoryHome['force_home'], 'home_id' => $this->directoryHome['page_id']));
             }
         }
         if ($atts['link']) {
             $rel = is_object($wp_rewrite) && $wp_rewrite->using_permalinks() ? 'rel="category tag"' : 'rel="category"';
             $url = cnTerm::permalink($category, 'category', array('force_home' => $this->directoryHome['force_home'], 'home_id' => $this->directoryHome['page_id']));
             $text .= '<a href="' . $url . '" ' . $rel . '>' . esc_html($category->name) . '</a>';
         } else {
             $text .= esc_html($category->name);
         }
         $items[] = apply_filters('cn_entry_output_category_item', sprintf('<%1$s class="cn-category-name cn_category cn-category-%2$d">%3$s%4$s</%1$s>', $atts['item_tag'], $category->term_id, $text, $count > $i && 'list' !== $atts['type'] ? esc_html($atts['separator']) : ''), $category, $count, $i, $atts, $this);
         $i++;
         // Increment here so the correct value is passed to the filter.
     }
     /*
      * Remove NULL, FALSE and empty strings (""), but leave values of 0 (zero).
      * Filter our these in case someone hooks into the `cn_entry_output_category_item` filter and removes a category
      * by returning an empty value.
      */
     $items = array_filter($items, 'strlen');
     if ('list' == $atts['type']) {
         $html .= sprintf('<%1$s class="cn-category-list">%2$s</%1$s>', 'unordered' === $atts['list'] ? 'ul' : 'ol', implode('', $items));
     } else {
         $html .= implode('', $items);
     }
     $html = apply_filters('cn_entry_output_category_container', sprintf('<%1$s class="cn-categories">%2$s</%1$s>' . PHP_EOL, $atts['container_tag'], $atts['before'] . $label . $html . $atts['after']), $atts);
     return $this->echoOrReturn($atts['return'], $html);
 }