/** * Render an checklist of terms. * * This is the Connections equivalent of @see wp_terms_checklist() in WordPress core ..wp-admin/wp-includes/template.php * * @access public * @since 8.2 * @static * * @param array $atts { * Optional. An array of arguments. * NOTE: Additionally, all valid options as supported in @see cnTerm::getTaxonomyTerms(). * * @type bool $show_count Whether or not to display the category count. * Default: FALSE * @type string $name The select name attribute. * Default: 'cat' * @type int $depth Controls how many levels in the hierarchy of categories are to be included in the list. * Default: 0 * Accepts: 0 - All categories and child categories. * -1 - All Categories displayed flat, not showing the parent/child relationships. * 1 - Show only top level/root parent categories. * n - Value of n (int) specifies the depth (or level) to descend in displaying the categories. * @type string $taxonomy The taxonomy tree to display. * Default: 'category' * Accepts: Any registered taxonomy. * @type mixed $selected The selected term ID(s) the term ID or array of term ID/s that are selected. * Default: 0 * @type bool $return Whether or not to return or echo the resulting HTML. * Default: FALSE * } * * @return string */ public static function render($atts = array()) { $out = ''; $defaults = array('orderby' => 'name', 'order' => 'ASC', 'show_count' => FALSE, 'hide_empty' => FALSE, 'name' => 'entry_category', 'depth' => 0, 'taxonomy' => 'category', 'selected' => 0, 'return' => FALSE); $atts = wp_parse_args($atts, $defaults); if (!is_array($atts['selected'])) { $atts['selected'] = array(absint($atts['selected'])); } else { array_walk($atts['selected'], 'absint'); } $walker = new self(); $walker->tree_type = $atts['taxonomy']; $terms = cnTerm::getTaxonomyTerms($atts['taxonomy'], $atts); if (!empty($terms)) { $out .= '<ul id="' . esc_attr($atts['taxonomy']) . 'checklist" class="' . esc_attr($walker->tree_type) . 'checklist form-no-clear">'; $out .= $walker->walk($terms, $atts['depth'], $atts); $out .= '</ul>'; } if ($atts['return']) { return $out; } echo $out; }
/** * Prepare links for the request. * * @since 8.5.26 * * @param object $term Term object. * * @return array Links for the given term. */ protected function prepare_links($term) { $base = $this->namespace . '/' . $this->base; $links = array('self' => array('href' => rest_url(trailingslashit($base) . $term->term_id)), 'collection' => array('href' => rest_url($base)), 'about' => array('href' => rest_url(sprintf('cn-api/v1/taxonomies/%s', $this->taxonomy)))); if ($term->parent) { $parent_term = cnTerm::get((int) $term->parent, $term->taxonomy); if ($parent_term) { $links['up'] = array('href' => rest_url(trailingslashit($base) . $parent_term->term_id), 'embeddable' => TRUE); } } //$taxonomy_obj = get_taxonomy( $term->taxonomy ); //if ( empty( $taxonomy_obj->object_type ) ) { // // return $links; //} //$post_type_links = array(); //foreach ( $taxonomy_obj->object_type as $type ) { // // $post_type_object = get_post_type_object( $type ); // // if ( empty( $post_type_object->show_in_rest ) ) { // // continue; // } // // $rest_base = ! empty( $post_type_object->rest_base ) ? $post_type_object->rest_base : $post_type_object->name; // $post_type_links[] = array( // 'href' => add_query_arg( $this->rest_base, $term->term_id, rest_url( sprintf( 'wp/v2/%s', $rest_base ) ) ), // ); //} //if ( ! empty( $post_type_links ) ) { // // $links['https://api.w.org/post_type'] = $post_type_links; //} return $links; }
/** * Returns category by ID. * * @param integer $id * @return object */ public function category($id) { return cnTerm::get($id, 'category'); }
/** * Add the the current Connections category description or entry bio excerpt as the page meta description. * * @access private * @since 0.7.8 * @static * * @uses cnQuery::getVar() * @uses esc_attr() * @uses strip_shortcodes() */ public static function metaDesc() { // Whether or not to filter the page title with the current directory location. if (!cnSettingsAPI::get('connections', 'seo_meta', 'page_desc')) { return; } $description = ''; if (cnQuery::getVar('cn-cat-slug')) { // If the category slug is a descendant, use the last slug from the URL for the query. $categorySlug = explode('/', cnQuery::getVar('cn-cat-slug')); if (isset($categorySlug[count($categorySlug) - 1])) { $categorySlug = $categorySlug[count($categorySlug) - 1]; } $term = cnTerm::getBy('slug', $categorySlug, 'category'); $category = new cnCategory($term); $description = $category->getExcerpt(array('length' => 160)); } if (cnQuery::getVar('cn-cat')) { if (is_array(cnQuery::getVar('cn-cat'))) { return; } $categoryID = cnQuery::getVar('cn-cat'); $term = cnTerm::getBy('id', $categoryID, 'category'); $category = new cnCategory($term); $description = $category->getExcerpt(array('length' => 160)); } if (cnQuery::getVar('cn-entry-slug')) { // Grab an instance of the Connections object. $instance = Connections_Directory(); $result = $instance->retrieve->entries(array('slug' => urldecode(cnQuery::getVar('cn-entry-slug')))); // Make sure an entry is returned and then echo the meta desc. if (!empty($result)) { $entry = new cnEntry($result[0]); $description = $entry->getExcerpt(array('length' => 160)); } } if (0 == strlen($description)) { return; } echo '<meta name="description" content="' . esc_attr(trim(strip_shortcodes(strip_tags(stripslashes($description))))) . '"/>' . "\n"; }
/** * Recursive function prepend a terms parent name and slug to the hierarchy string. * * @access public * @since 8.5.5 * * @param object $term * @param string $text */ private function _buildHierarchy($term, &$text) { if ($term->parent) { $parent = cnTerm::get($term->parent, $term->taxonomy); if (0 == strlen($text)) { $text = "{$parent->name}|{$parent->slug}"; } else { $text = "{$parent->name}|{$parent->slug}" . ' > ' . $text; } $this->_buildHierarchy($parent, $text); } }
/** * 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('— ', 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 “%s”', '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; }
/** * Retrieve the entry terms by taxonomy. * * @access public * @since 8.2 * @static * * @param int $id * @param string $taxonomy * @param array $atts Optional. An array of arguments. @see cnTerm::getRelationships() for accepted arguments. * * @return mixed array|WP_Error An array of terms by taxonomy associated to an entry. */ public static function entryTerms($id, $taxonomy, $atts = array()) { /** @todo Check that entry exists */ //if ( ! $id = get_entry( $id ) ) { // return false; //} $terms = cnTerm::getRelationshipsCache($id, $taxonomy); if (FALSE === $terms) { $terms = cnTerm::getRelationships($id, $taxonomy, $atts); wp_cache_add($id, $terms, "cn_{$taxonomy}_relationships"); } else { /** * Filter the list of terms attached to the given entry. * * @since 8.2 * * @param array|WP_Error $terms List of attached terms, or WP_Error on failure. * @param int $id Post ID. * @param string $taxonomy Name of the taxonomy. * @param array $atts An array of arguments for retrieving terms for the given object. */ $terms = apply_filters('cn_get_object_terms', $terms, $id, $taxonomy, $atts); } return $terms; }
/** * 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"> (' . 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. }
/** * Write the CSV rows for the current step. * * @access public * @since 8.5.1 */ public function writeRows() { $results = $this->getData(); $rows = ''; if (!empty($results)) { // Go through each entry... foreach ($results as $entry) { $fieldCount = count($this->fields); $row = ''; // ...and go through each cell the user wants to export, and match it with the cell in the entry... for ($i = 0; $i < $fieldCount; $i++) { // ...then find out if it's a breakout cell and process it properly... switch ($this->fields[$i]['type']) { case 1: // Export a standard breakout; just list them all in the order requested... $row .= $this->exportBreakoutCell($this->fields[$i], $entry->id); break; case 2: // Process category table and list all categories in a single cell... $terms = array(); $results = $this->getTerms($entry->id, 'category'); foreach ($results as $term) { $terms[] = $term->name; } $row .= $this->escapeAndQuote(implode(',', $terms)) . ','; break; case 3: $count = $this->getTermCount('category'); $terms = array(); // Process the category table by breaking them out in separate cells, // Prepare an empty frame of the category cells... for ($j = 0; $j < $count + 1; $j++) { // Make an array filled with empty cells $terms[$j] = '"",'; } // Now start filling in the empty cells with data... $row = $this->getTerms($entry->id, 'category'); $j = 0; foreach ($row as $result) { $terms[$j] = $this->escapeAndQuote($result->name) . ','; $j++; } $row .= implode('', $terms); break; case 4: // Export breakout data from the serialized option cell. $row .= $this->exportBreakoutOptionsCell($this->fields[$i], $entry); break; case 5: $data = ''; $meta = cnMeta::get('entry', $entry->id, $this->fields[$i]['field'], TRUE); if (!empty($meta)) { $data = cnFormatting::maybeJSONencode($meta); } $row .= $this->escapeAndQuote($data) . ','; break; case 6: $terms = array(); $parent = $this->fields[$i]['child_of']; $results = $this->getTerms($entry->id, 'category'); foreach ($results as $term) { $terms[] = $parent . ':' . $term->term_id; if (cnTerm::isAncestorOf($parent, $term->term_id, 'category')) { $terms[] = $term->name; } } $row .= $this->escapeAndQuote(implode(',', $terms)) . ','; break; default: // If no breakout type is defined, only display the cell data... $row .= $this->escapeAndQuote($entry->{$this->fields[$i]['field']}) . ','; break; } } // Trim the trailing comma and space, then add newline. $rows .= rtrim($row, ',') . "\r\n"; } // Now write the data... $this->write($rows); return $rows; } return FALSE; }
/** * 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'] ? ' (' . 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; }
/** * Deletes the category from the database via the cnTerm class. * * @return bool The success or error message. */ public function delete() { // @todo Add option for user to set the default category, which should not be able to be deleted. //$defaults['default'] = get_option( 'cn_default_category' ); // Temporarily hard code the default category to the Uncategorized category // and ensure it can not be deleted. This should be removed when the default // category can be set by the user. $default_category = cnTerm::getBy('slug', 'uncategorized', 'category'); $defaults['default'] = $default_category->term_id; // Do not change the default category. // This should be able to be removed after the user configurable default category is implemented. if ($this->id == $default_category->term_id) { cnMessage::set('error', 'category_delete_uncategorized'); return FALSE; } $result = cnTerm::delete($this->id, 'category'); if (is_wp_error($result)) { cnMessage::set('error', $result->get_error_message()); return FALSE; } else { cnMessage::set('success', 'category_deleted'); return TRUE; } }
/** * Add the "Uncategorized" category" * * @access private * @since 0.7.5 * * @return void */ private static function addDefaultCategory() { $term = cnTerm::getBy('slug', 'uncategorized', 'category'); if (!$term) { $attributes['slug'] = ''; $attributes['parent'] = 0; $attributes['description'] = __('Entries not assigned to a category will automatically be assigned to this category and deleting a category which has been assigned to an entry will reassign that entry to this category. This category can not be edited or deleted.', 'connections'); cnTerm::insert(__('Uncategorized', 'connections'), 'category', $attributes); } }
/** * Render an checklist of terms. * * This is the Connections equivalent of @see wp_terms_checklist() in WordPress core ..wp-admin/wp-includes/template.php * * @access public * @since 8.2.4 * @static * * @uses wp_parse_args() * @uses cnTerm::getTaxonomyTerms() * @uses wp_parse_id_list() * @uses is_wp_error() * @uses esc_attr() * @uses apply_filters * @uses checked() * @uses esc_html() * @uses Walker::walk() * * @param array $atts { * Optional. An array of arguments. * NOTE: Additionally, all valid options as supported in @see cnTerm::getTaxonomyTerms(). * * @type string $taxonomy The taxonomy tree to display. * Default: 'category' * @type bool $hierarchical Whether to include terms that have non-empty descendants, even if 'hide_empty' is set to TRUE. * Default: TRUE * @type string $name The select name attribute. * Default: 'cn-cat' * @type bool $show_select_all Whether or not to render the $show_option_all option. * Default: TRUE * @type string $show_option_all A non-blank value causes the display of a link to the directory home page. * Default: ''. The default is not to display a link. * Accepts: Any valid string. * @type bool $show_count Whether or not to display the category count. * Default: FALSE * @type bool $hide_empty Whether or not to display empty terms. * Default: FALSE * @type int $depth Controls how many levels in the hierarchy of categories are to be included in the list. * Default: 0 * Accepts: 0 - All categories and child categories. * -1 - All Categories displayed flat, not showing the parent/child relationships. * 1 - Show only top level/root parent categories. * n - Value of n (int) specifies the depth (or level) to descend in displaying the categories. * @type array $parent_id * @type array $selected The selected term IDs. * Default: 0 * @type string $before Content to be render before the label and select. * Default: '' * @type string $after Content to be render after the label and select. * Default: '' * @type bool $return Whether or not to return or echo the resulting HTML. * Default: FALSE * } * * @return string */ public static function render($atts = array()) { $out = ''; $defaults = array('taxonomy' => 'category', 'hierarchical' => TRUE, 'name' => 'cn-cat', 'show_select_all' => TRUE, 'show_option_all' => __('Select Category', 'connections'), 'show_count' => FALSE, 'hide_empty' => FALSE, 'depth' => 0, 'parent_id' => array(), 'selected' => 0, 'before' => '', 'after' => '', 'return' => FALSE); $atts = wp_parse_args($atts, $defaults); $walker = new self(); $walker->tree_type = $atts['taxonomy']; if (empty($atts['parent_id'])) { $terms = cnTerm::getTaxonomyTerms($atts['taxonomy'], $atts); } else { $atts['parent_id'] = wp_parse_id_list($atts['parent_id']); $terms = cnTerm::getTaxonomyTerms($atts['taxonomy'], array_merge($atts, array('include' => $atts['parent_id'], 'child_of' => 0))); // If any of the `parent_id` is not a root parent (where $term->parent = 0) set it parent ID to `0` // so the term tree will be properly constructed. foreach ($terms as $term) { if (0 !== $term->parent) { $term->parent = 0; } } foreach ($atts['parent_id'] as $termID) { $children = cnTerm::getTaxonomyTerms($atts['taxonomy'], array_merge($atts, array('child_of' => $termID))); if (!is_wp_error($children)) { $terms = array_merge($terms, $children); } } } if (!empty($terms)) { $out .= '<ul class="cn-' . esc_attr($atts['taxonomy']) . '-radio-group">' . PHP_EOL; if ($atts['show_select_all'] && $atts['show_option_all']) { /** This filter is documented in includes/template/class.template-walker-term-select.php */ $show_option_all = apply_filters('cn_list_cats', $atts['show_option_all']); $type = esc_attr($walker->tree_type); $out .= "<li id='cn-{$type}-0'>" . '<label><input value="0" type="radio" name="' . esc_attr($atts['name']) . '" id="cn-in-' . $type . '-0"' . checked(in_array(0, (array) $atts['selected']), TRUE, FALSE) . ' /> ' . esc_html($show_option_all) . '</label>'; $out .= '</li>' . PHP_EOL; } $out .= $walker->walk($terms, $atts['depth'], $atts); $out .= '</ul>' . PHP_EOL; } $out = (empty($atts['before']) ? '' : $atts['before']) . $out . (empty($atts['after']) ? '' : $atts['after']); if ($atts['return']) { return $out; } echo $out; }
/** * Add, update or delete the entry categories. * * @access public * @since 0.8 * @param string $action The action to being performed to an entry. * @param int $id The entry ID. * * @return void */ public static function processEntryCategory($action, $id) { // Grab an instance of the Connections object. $instance = Connections_Directory(); /* * Save the entry category(ies). If none were checked, send an empty array * which will add the entry to the default category. */ if (isset($_POST['entry_category']) && !empty($_POST['entry_category'])) { $instance->term->setTermRelationships($id, $_POST['entry_category'], 'category'); } else { // @todo Add option for user to set the default category, which should not be able to be deleted. //$defaults['default'] = get_option( 'cn_default_category' ); // Temporarily hard code the default category to the Uncategorized category // and ensure it can not be deleted. This should be removed when the default // category can be set by the user. $default_category = cnTerm::getBy('slug', 'uncategorized', 'category'); $instance->term->setTermRelationships($id, $default_category->term_id, 'category'); } }
/** * Get the default category ID. * * NOTE: This is also the callback for the `default_option_{name}` filter @see get_option(). * * NOTE: Uses the @see get_option() and @see update_option() functions instead of the @see cnSettingsAPI() * because it is used in places where the cnSettingsAPI() has not yet been fully initialized. * * @access public * @since 8.3.3 * @static * * @uses remove_filter() * @uses get_option() * @uses cnTerm::exists() * @uses cnTerm::getBy() * @uses cnTerm::insert() * @uses update_option() * @uses is_wp_error() * @uses add_filter() * * @return int */ public static function getDefaultCategoryID() { $id = 0; // Remove filter to prevent an infinite loop. remove_filter('default_option_cn_default_category', array(__CLASS__, 'getDefaultCategoryID')); // Use get_option() rather than cnSettingsAPI::get() because the class may not yet be initialized. $category = get_option('connections_category'); // Check to ensure the default category ID is saved in the options table before returning it. if (FALSE === $category || !isset($category['default']) || empty($category['default'])) { // If there was no default category set, check for the "Uncategorized" category. If it exists return its // `id` and if it does not, then create it an return the `id`. if (cnTerm::exists('uncategorized', 'category')) { $category = cnTerm::getBy('slug', 'uncategorized', 'category', ARRAY_A); // Ensure nothing went wrong when checking for the "Uncategorized" category. // If not, save the `id` in the options table. if (FALSE !== $category) { $id = $category['term_id']; // Use update_option() rather than cnSettingsAPI::set() because the class may not yet be initialized. update_option('connections_category', array('default' => $id)); } } else { $category = cnTerm::insert(__('Uncategorized', 'connections'), 'category'); // Ensure nothing went wrong when inserting the "Uncategorized" category. // If not, save the `id` in the options table. if (!is_wp_error($category)) { $id = $category['term_id']; // Use update_option() rather than cnSettingsAPI::set() because the class may not yet be initialized. update_option('connections_category', array('default' => $id)); } } } else { $id = $category['default']; } // Add the filter back. add_filter('default_option_cn_default_category', array(__CLASS__, 'getDefaultCategoryID')); /** * Allows the opportunity to change the default category. * * @since 8.3.3 * * @param int $id The default category ID. */ return apply_filters('cn_default_category', $id); }
/** * Deletes the category from the database via the cnTerm class. * * @return bool The success or error message. */ public function delete() { $default = get_option('cn_default_category'); if ($this->id == $default) { cnMessage::set('error', 'category_delete_default'); return FALSE; } $result = cnTerm::delete($this->id, 'category'); if (is_wp_error($result)) { cnMessage::set('error', $result->get_error_message()); return FALSE; } else { cnMessage::set('success', 'category_deleted'); return TRUE; } }
/** * Retrieve the terms in a given taxonomy or list of taxonomies. * * NOTE: This is the Connections equivalent of @see get_terms() in WordPress core ../wp-includes/taxonomy.php * * Filters: * cn_get_terms_atts - The method variables. * Passes: (array) $atts, (array) $taxonomies * Return: $atts * * cn_get_terms_fields - The fields for the SELECT query clause. * Passes: (array) $select, (array) $atts, (array) $taxonomies * Return: $select * * cn_term_inclusions - Query clause which includes terms. * Passes: (string) $inclusions, (array) $atts, (array) $taxonomies * Return: $inclusions * * cn_term_exclusions - Query clause which excludes terms. * Passes: (string) $exclusions, (array) $atts, (array) $taxonomies * Return: $exclusions * * cn_term_orderby - The ORDER BY query clause. * Passes: (string) $orderBy, (array) $atts, (array) $taxonomies * Return: $orderBy * * cn_terms_clauses - An array containing the the query clause segments. * Passes: (array) $pieces, (array) $taxonomies, (array) $atts * Return: $pieces * * Accepted option for the $atts property are: * * get ( string ) * Default: '' * Valid: all * If set to 'all' instead of its default empty string, * returns terms regardless of ancestry or whether the terms are empty. * * fields ( string ) * Default: 'all' * Valid: all | ids | id=>parent | names | count | id=>name | id=>slug * Default is 'all', which returns an array of term objects. * If 'fields' is 'ids' or 'names', returns an array of integers or strings, respectively. * * include ( string | array ) * Default: array() * Valid: An indexed array, comma- or space-delimited string of term_id. * * exclude_tree ( string | array ) * Default: array() * Valid: An indexed array, comma- or space-delimited string of term_id. * If 'include' is non-empty, 'exclude_tree' is ignored. * * exclude ( string | array ) * Default: array() * Valid: An indexed array, comma- or space-delimited string of term_id. * If 'include' is non-empty, 'exclude' is ignored. * * slug ( string | array ) * Default: '' * Slug or array of slugs to return term(s) for. * * hide_empty ( bool ) * Default: TRUE * Will not return empty terms, which means terms whose count is 0. * * hierarchical ( bool ) * Default: TRUE * Whether to include terms that have non-empty descendants, even if 'hide_empty' is set to TRUE. * * orderby ( string | array ) * Default: name * Valid: term_id | name | slug | term_group | parent | count | include * * order ( string | array ) * Default: ASC * Valid: ASC | DESC * * number ( int ) * Default: 0 * The maximum number of terms to return. Default is to return them all. * * offset ( int ) * Default: 0 * The number by which to offset the terms query. * * search ( string ) * Default: '' * Returned terms' names will contain the value of 'search', case-insensitive. * * name__like ( string ) * Default: '' * Return terms' names will contain the value of 'name__like', case-insensitive. * * description__like ( string ) * Default: '' * Return terms' descriptions will contain the value of 'description__like', case-insensitive. * * child_of ( int ) * Default: 0 * The 'child_of' argument, when used, should be set to the integer of a term ID. * If set to a non-zero value, all returned terms will be descendants * of that term according to the given taxonomy. * Hence 'child_of' is set to 0 if more than one taxonomy is passed in $taxonomies, * because multiple taxonomies make term ancestry ambiguous. * * parent ( string | int ) * Default: '' * The integer of a term ID. * If set to an integer value, all returned terms will have as an immediate * ancestor the term whose ID is specified by that integer according to the given taxonomy. * The 'parent' argument is different from 'child_of' in that a term X is considered a 'parent' * of term Y only if term X is the father of term Y, not its grandfather or great-grandfather, etc. * * pad_counts ( bool ) * Default: FALSE * If set to true, include the quantity of a term's children * in the quantity of each term's 'count' property. * * @access public * @since 8.1 * @static * * @global $wpdb * * @param string|array $taxonomies Taxonomy name or array of taxonomy names. * @param array $atts * * @uses apply_filters() * @uses wp_parse_args() * @uses wp_parse_id_list() * @uses sanitize_title() * @uses wpdb::prepare() * @uses $wpdb::esc_like() * @uses absint() * @uses wpdb::get_results() * @uses cnTerm::filter() * @uses cnTerm::descendants() * @uses cnTerm::childrenIDs() * @uses cnTerm::padCounts() * @uses cnTerm::children() * * @return array|WP_Error Indexed array of term objects. Will return WP_Error, if any of $taxonomies do not exist.* */ public static function getTaxonomyTerms($taxonomies = array('category'), $atts = array()) { /** @var $wpdb wpdb */ global $wpdb; $select = array(); $where = array(); $orderBy = array(); $orderByClause = ''; /* * @TODO $taxonomies need to be checked against registered taxonomies. * Presently $taxonomies only support a string rather than array. * Additionally, category is the only supported taxonomy. */ $single_taxonomy = !is_array($taxonomies) || 1 === count($taxonomies); if (!is_array($taxonomies)) { $taxonomies = array($taxonomies); } $defaults = array('get' => '', 'orderby' => 'name', 'order' => 'ASC', 'hide_empty' => TRUE, 'exclude' => array(), 'exclude_tree' => array(), 'include' => array(), 'fields' => 'all', 'slug' => '', 'parent' => '', 'hierarchical' => TRUE, 'child_of' => 0, 'name__like' => '', 'meta_query' => array(), 'pad_counts' => FALSE, 'offset' => 0, 'number' => 0, 'search' => ''); /** * Filter the terms query arguments. * * @since 8.1 * * @param array $atts An array of arguments. * @param string|array $taxonomies A taxonomy or array of taxonomies. */ $atts = apply_filters('cn_get_terms_args', $atts, $taxonomies); $atts = wp_parse_args($atts, $defaults); // @TODO Implement is_taxonomy_hierarchical(). if (!$single_taxonomy || '' !== $atts['parent'] && 0 !== $atts['parent']) { $atts['child_of'] = 0; $atts['hierarchical'] = FALSE; $atts['pad_counts'] = FALSE; } if ('all' == $atts['get']) { $atts['child_of'] = 0; $atts['hide_empty'] = 0; $atts['hierarchical'] = FALSE; $atts['pad_counts'] = FALSE; } if ($atts['child_of']) { $hierarchy = self::childrenIDs(reset($taxonomies)); if (!isset($hierarchy[$atts['child_of']])) { return array(); } } if ($atts['parent']) { $hierarchy = self::childrenIDs(reset($taxonomies)); if (!isset($hierarchy[$atts['parent']])) { return array(); } } // $args can be whatever, only use the args defined in defaults to compute the key $filter_key = has_filter('cn_term_exclusions') ? serialize($GLOBALS['wp_filter']['cn_term_exclusions']) : ''; $key = md5(serialize(wp_array_slice_assoc($atts, array_keys($defaults))) . serialize($taxonomies) . $filter_key); $last_changed = wp_cache_get('last_changed', 'cn_terms'); if (!$last_changed) { $last_changed = microtime(); wp_cache_set('last_changed', $last_changed, 'cn_terms'); } $cache_key = "cn_get_terms:{$key}:{$last_changed}"; $cache = wp_cache_get($cache_key, 'cn_terms'); if (FALSE !== $cache) { /** * Filter the given taxonomy's terms cache. * * @since 8.1.6 * * @param array $cache Cached array of terms for the given taxonomy. * @param string|array $taxonomies A taxonomy or array of taxonomies. * @param array $args An array of arguments to get terms. */ $cache = apply_filters('cn_terms', $cache, $taxonomies, $atts); return $cache; } /* * Construct the ORDER By query clause. */ if (is_array($atts['orderby'])) { foreach ($atts['orderby'] as $i => $value) { if (!isset($order)) { $order = 'ASC'; } switch ($value) { case 'id': case 'term_id': $orderField = 't.term_id'; break; case 'slug': $orderField = 't.slug'; break; case 'include': $include = implode(',', wp_parse_id_list($atts['include'])); $orderField = "FIELD( t.term_id, {$include} )"; break; case 'term_group': $orderField = 't.term_group'; break; case 'none': $orderField = ''; // If an `none` order field was supplied, break out of both the switch and foreach statements. break 2; case 'parent': $orderField = 'tt.parent'; break; case 'count': $orderField = 'tt.count'; break; default: $orderField = 't.name'; break; } // Set the $order to align with $atts['orderby']. if (is_array($atts['order']) && isset($atts['order'][$i])) { $order = $atts['order'][$i]; // If an aligned $atts['order'] does not exist use the last $order set otherwise use $atts['order']. } else { $order = is_array($atts['order']) ? $order : $atts['order']; } $order = strtoupper($order); $order = in_array($order, array('ASC', 'DESC')) ? $order : 'ASC'; $orderBy[] = sprintf('%s %s', $orderField, $order); } // The @var $value will be set to the last value from the $atts['orderby'] foreach loop. // If a `none` $atts['orderby'] was found in the supplied array, no order by clause will be set. if (!empty($orderBy) && $value != 'none') { $orderByClause = 'ORDER BY ' . implode(', ', $orderBy); } } else { switch ($atts['orderby']) { case 'id': case 'term_id': $atts['orderby'] = 't.term_id'; break; case 'slug': $atts['orderby'] = 't.slug'; break; case 'include': $include = implode(',', wp_parse_id_list($atts['include'])); $atts['orderby'] = "FIELD( t.term_id, {$include} )"; break; case 'term_group': $atts['orderby'] = 't.term_group'; break; case 'none': $atts['orderby'] = ''; break; case 'parent': $atts['orderby'] = 'tt.parent'; break; case 'count': $atts['orderby'] = 'tt.count'; break; default: $atts['orderby'] = 't.name'; break; } if (is_array($atts['order'])) { // $atts['orderby'] was a string but an array was passed for $atts['order'], assume the 0 index. $order = $atts['order'][0]; } else { $order = $atts['order']; } if (!empty($atts['orderby'])) { $order = strtoupper($order); $order = in_array($order, array('ASC', 'DESC')) ? $order : 'ASC'; $orderByClause = 'ORDER BY ' . sprintf('%s %s', $atts['orderby'], $order); } } /* * Filter the ORDER BY clause of the terms query. * * @since 8.1 * * @param string $orderBy ORDER BY clause of the terms query. * @param array $atts An array of terms query arguments. * @param string|array $taxonomies A taxonomy or array of taxonomies. */ $orderBy = apply_filters('cn_terms_orderby', $orderByClause, $atts, $taxonomies); /* * Start construct the WHERE query clause. */ $where[] = 'tt.taxonomy IN (\'' . implode('\', \'', $taxonomies) . '\')'; /* * Define the included terms. */ $inclusions = ''; if (!empty($atts['include'])) { $atts['exclude'] = ''; $atts['exclude_tree'] = ''; $inclusions = implode(',', wp_parse_id_list($atts['include'])); } if (!empty($inclusions)) { $inclusions = 'AND t.term_id IN ( ' . $inclusions . ' )'; } /** * Filter the terms to be included in the terms query. * * @since 8.1 * * @param string $inclusions IN clause of the terms query. * @param array $atts An array of terms query arguments. * @param string|array $taxonomies A taxonomy or array of taxonomies. */ $inclusions = apply_filters('cn_term_inclusions', $inclusions, $atts, $taxonomies); if (!empty($inclusions)) { $where[] = $inclusions; } /* * Define the excluded terms. */ $exclusions = ''; if (!empty($atts['exclude_tree'])) { $atts['exclude_tree'] = wp_parse_id_list($atts['exclude_tree']); $excluded_children = $atts['exclude_tree']; foreach ($atts['exclude_tree'] as $extrunk) { $excluded_children = array_merge($excluded_children, (array) cnTerm::getTaxonomyTerms($taxonomies[0], array('child_of' => intval($extrunk), 'fields' => 'ids', 'hide_empty' => 0))); } $exclusions = implode(',', array_map('intval', $excluded_children)); } if (!empty($atts['exclude'])) { $exterms = wp_parse_id_list($atts['exclude']); if (empty($exclusions)) { $exclusions = implode(',', $exterms); } else { $exclusions .= ', ' . implode(',', $exterms); } } if (!empty($exclusions)) { $exclusions = 'AND t.term_id NOT IN (' . $exclusions . ')'; } /** * Filter the terms to exclude from the terms query. * * @since 8.1 * * @param string $exclusions NOT IN clause of the terms query. * @param array $atts An array of terms query arguments. * @param string|array $taxonomies A taxonomy or array of taxonomies. */ $exclusions = apply_filters('cn_term_exclusions', $exclusions, $atts, $taxonomies); if (!empty($exclusions)) { $where[] = $exclusions; } if (!empty($atts['slug'])) { if (is_array($atts['slug'])) { $slug = array_map('sanitize_title', $atts['slug']); $where[] = " AND t.slug IN ('" . implode("', '", $slug) . "')"; } else { $slug = sanitize_title($atts['slug']); $where[] = " AND t.slug = '{$slug}'"; } } if (!empty($atts['name__like'])) { //$atts['name__like'] = like_escape( $atts['name__like'] ); $where[] = $wpdb->prepare(" AND t.name LIKE %s", '%' . $wpdb->esc_like($atts['name__like']) . '%'); //$where[] = $wpdb->prepare( 'AND t.name LIKE %s', '%' . $atts['name__like'] . '%' ); } if (!empty($atts['description__like'])) { //$atts['description__like'] = like_escape( $atts['description__like'] ); $where[] = $wpdb->prepare(" AND tt.description LIKE %s", '%' . $wpdb->esc_like($atts['description__like']) . '%'); //$where[] = $wpdb->prepare( 'AND tt.description LIKE %s', '%' . $atts['description__like'] . '%' ); } if ('' !== $atts['parent']) { $where[] = $wpdb->prepare('AND tt.parent = %d', $atts['parent']); } if ('count' == $atts['fields']) { $atts['hierarchical'] = FALSE; } if ($atts['hide_empty'] && !$atts['hierarchical']) { $where[] = 'AND tt.count > 0'; } // Do not limit the query results when we have to descend the family tree. if ($atts['number'] && !$atts['hierarchical'] && !$atts['child_of'] && '' === $atts['parent']) { $atts['number'] = absint($atts['number']); $atts['offset'] = absint($atts['offset']); if ($atts['offset']) { $limit = $wpdb->prepare('LIMIT %d,%d', $atts['offset'], $atts['number']); } else { $limit = $wpdb->prepare('LIMIT %d', $atts['number']); } } else { $limit = ''; } if (!empty($atts['search'])) { //$atts['search'] = like_escape( $atts['search'] ); $atts['search'] = $wpdb->esc_like($atts['search']); $where[] = $wpdb->prepare('AND ( (t.name LIKE %s) OR (t.slug LIKE %s) )', '%' . $atts['search'] . '%', '%' . $atts['search'] . '%'); } switch ($atts['fields']) { case 'all': $select = array('t.*', 'tt.*'); break; case 'ids': case 'id=>parent': $select = array('t.term_id', 'tt.parent', 'tt.count'); break; case 'names': $select = array('t.term_id', 'tt.parent', 'tt.count', 't.name'); break; case 'count': $orderBy = ''; //$order = ''; $select = array('COUNT(*)'); break; case 'id=>name': $select = array('t.term_id', 't.name'); break; case 'id=>slug': $select = array('t.term_id', 't.slug'); break; } /** * Filter the fields to select in the terms query. * * @since 8.1 * * @param array $select An array of fields to select for the terms query. * @param array $atts An array of term query arguments. * @param string|array $taxonomies A taxonomy or array of taxonomies. */ $fields = implode(', ', apply_filters('cn_get_terms_fields', $select, $atts, $taxonomies)); $join = 'INNER JOIN ' . CN_TERM_TAXONOMY_TABLE . ' AS tt ON t.term_id = tt.term_id'; $pieces = array('fields', 'join', 'where', 'orderBy', 'limit'); /** * Filter the terms query SQL clauses. * * @since 8.1 * * @param array $pieces Terms query SQL clauses. * @param string|array $taxonomies A taxonomy or array of taxonomies. * @param array $atts An array of terms query arguments. */ $clauses = apply_filters('cn_terms_clauses', compact($pieces), $taxonomies, $atts); foreach ($pieces as $piece) { ${$piece} = isset($clauses[$piece]) ? $clauses[$piece] : ''; } $sql = sprintf('SELECT %1$s FROM %2$s AS t %3$s WHERE %4$s %5$s%6$s', $fields, CN_TERMS_TABLE, $join, implode(' ', $where), $orderBy, empty($limit) ? '' : ' ' . $limit); if ('count' == $atts['fields']) { $term_count = $wpdb->get_var($sql); return $term_count; } $terms = $wpdb->get_results($sql); if ('all' == $atts['fields']) { foreach ($taxonomies as $taxonomy) { update_term_cache($terms, 'cn_' . $taxonomy); } } if (empty($terms)) { wp_cache_add($cache_key, array(), 'cn_terms', DAY_IN_SECONDS); $terms = apply_filters('cn_terms', array(), $taxonomies, $atts); return $terms; } if ($atts['child_of']) { $children = self::childrenIDs(reset($taxonomies)); if (!empty($children)) { $terms = self::descendants($atts['child_of'], $terms, reset($taxonomies)); } } /* * @todo Add method to adjust counts based on user visibility permissions. */ // Update term counts to include children. if ($atts['pad_counts'] && 'all' == $atts['fields']) { self::padCounts($terms, reset($taxonomies)); } // Make sure we show empty categories that have children. if ($atts['hierarchical'] && $atts['hide_empty'] && is_array($terms)) { foreach ($terms as $k => $term) { if (!$term->count) { $children = self::children($term->term_id, reset($taxonomies)); if (is_array($children)) { foreach ($children as $child_id) { $child = self::filter($child_id, reset($taxonomies)); if ($child->count) { continue 2; } } } // It really is empty unset($terms[$k]); } } } reset($terms); $_terms = array(); if ('id=>parent' == $atts['fields']) { while ($term = array_shift($terms)) { $_terms[$term->term_id] = $term->parent; } } elseif ('ids' == $atts['fields']) { while ($term = array_shift($terms)) { $_terms[] = $term->term_id; } } elseif ('names' == $atts['fields']) { while ($term = array_shift($terms)) { $_terms[] = $term->name; } } elseif ('id=>name' == $atts['fields']) { while ($term = array_shift($terms)) { $_terms[$term->term_id] = $term->name; } } elseif ('id=>slug' == $atts['fields']) { while ($term = array_shift($terms)) { $_terms[$term->term_id] = $term->slug; } } if (!empty($_terms)) { $terms = $_terms; } if ($atts['number'] && is_array($terms) && count($terms) > $atts['number']) { $terms = array_slice($terms, $atts['offset'], $atts['number']); } wp_cache_add($cache_key, $terms, 'cn_terms', DAY_IN_SECONDS); $terms = apply_filters('cn_terms', $terms, $taxonomies, $atts); return $terms; }
/** * Display or retrieve the HTML select list of terms. * * This is the Connections equivalent of @see wp_dropdown_categories() in WordPress core ../wp-includes/category-template.php * * @access public * @since 8.2.4 * @static * * @uses wp_parse_args() * @uses cnTerm::getTaxonomyTerms() * @uses esc_attr() * @uses sanitize_html_class() * @uses apply_filters() * @uses Walker::walk() * @uses selected() * * @param array $atts { * Optional. An array of arguments. * NOTE: Additionally, all valid options as supported in @see cnTerm::getTaxonomyTerms(). * * @type string $taxonomy The taxonomy tree to display. * Default: 'category' * @type bool $hierarchical Whether to include terms that have non-empty descendants, even if 'hide_empty' is set to TRUE. * Default: TRUE * @type string $type The output type of the categories. * Default: select * Accepts: select || multiselect * @type bool $group Whether or not to create option groups using the root parent as the group label. * Default: FALSE * @type bool $hide_if_empty Whether or not to show the select if no terms are returned by term query. * Default: FALSE * @type string $name The select name attribute. * Default: 'cn-cat' * @type string $id The select id attribute. * Default: '' * @type array $class An array if classes to applied to the select. * Default: array('cn-category-select') * @type array $style An array of style to applied inline where the key is the style attribute and the value is the style attribute value. * Default: array() * @type bool $enhanced Whether of not apply the required attributes for the Chosen jQuery plugin. * Default: TRUE * @type string $on_change An inline JavaScript on_change event. * Default: '' * Accepts: Any valid inline JavaScript. * @type int $tab_index The tab index of the select. * Default: 0 * @type bool $show_select_all Whether or not to render the $show_option_all option. * Default: TRUE * @type string $show_option_all A non-blank value causes the display of a link to the directory home page. * Default: ''. The default is not to display a link. * Accepts: Any valid string. * @type string $show_option_none Set the text to show when no categories are listed. * Default: 'No Categories' * Accepts: Any valid string. * @type string $option_none_value Value to use when no term is selected. * Default: -1 * Accepts: Any valid int/string for an option value attribute. * @type string $default The default string to show as the first item in the list. * Default: 'Select Category' * @type bool $show_count Whether or not to display the category count. * Default: FALSE * @type bool $hide_empty Whether or not to display empty terms. * Default: FALSE * @type int $depth Controls how many levels in the hierarchy of categories are to be included in the list. * Default: 0 * Accepts: 0 - All categories and child categories. * -1 - All Categories displayed flat, not showing the parent/child relationships. * 1 - Show only top level/root parent categories. * n - Value of n (int) specifies the depth (or level) to descend in displaying the categories. * @type array $parent_id * @type array $selected The selected term IDs. * Default: 0 * @type string $label The label to render with the select. * Default: '' * @type string $before Content to be render before the label and select. * Default: '' * @type string $after Content to be render after the label and select. * Default: '' * @type string $layout Tokens which can be sued to control the order of the label and select. * Default: '%label%%field%' * Accepts: %label% %field% * @type bool $return Whether or not to return or echo the resulting HTML. * Default: FALSE * } * * @return string */ public static function render($atts = array()) { $select = ''; $out = ''; $defaults = array('taxonomy' => 'category', 'hierarchical' => TRUE, 'type' => 'select', 'group' => FALSE, 'hide_if_empty' => FALSE, 'name' => 'cn-cat', 'id' => '', 'class' => array('cn-category-select'), 'style' => array(), 'enhanced' => TRUE, 'on_change' => '', 'tab_index' => 0, 'show_select_all' => TRUE, 'show_option_all' => '', 'show_option_none' => '', 'option_none_value' => -1, 'default' => __('Select Category', 'connections'), 'show_count' => FALSE, 'hide_empty' => FALSE, 'depth' => 0, 'parent_id' => array(), 'selected' => 0, 'label' => '', 'before' => '', 'after' => '', 'layout' => '%label%%field%', 'return' => FALSE); $atts = wp_parse_args($atts, $defaults); if (wp_is_mobile()) { $atts['enhanced'] = FALSE; } // The field parts to be searched for in $atts['layout']. $search = array('%label%', '%field%'); // An array to store the replacement strings for the label and field. $replace = array(); $walker = new self(); $walker->tree_type = $atts['taxonomy']; if (!isset($atts['pad_counts']) && $atts['show_count'] && $atts['hierarchical']) { // Padding the counts is ideal, but really, really, bloats the memory required. $atts['pad_counts'] = FALSE; } if (empty($atts['parent_id'])) { $terms = cnTerm::getTaxonomyTerms($atts['taxonomy'], $atts); } else { $atts['parent_id'] = wp_parse_id_list($atts['parent_id']); $terms = cnTerm::getTaxonomyTerms($atts['taxonomy'], array_merge($atts, array('include' => $atts['parent_id'], 'child_of' => 0))); // If any of the `parent_id` is not a root parent (where $term->parent = 0) set it parent ID to `0` // so the term tree will be properly constructed. foreach ($terms as $term) { if (0 !== $term->parent) { $term->parent = 0; } } foreach ($atts['parent_id'] as $termID) { $children = cnTerm::getTaxonomyTerms($atts['taxonomy'], array_merge($atts, array('child_of' => $termID))); if (!is_wp_error($children)) { $terms = array_merge($terms, $children); } } } if (!$atts['hide_if_empty'] || !empty($terms)) { //$out .= PHP_EOL . "<select name='$name' id='$id' class='$class' $tab_index_attribute>" . PHP_EOL; // Add the 'cn-enhanced-select' class for the jQuery Chosen Plugin will enhance the drop down. if ($atts['enhanced']) { $atts['class'] = array_merge((array) $atts['class'], array('cn-enhanced-select')); } // Create the field label, if supplied. $replace[] = !empty($atts['label']) ? cnHTML::label(array('for' => $atts['id'], 'label' => $atts['label'], 'return' => TRUE)) : ''; $select .= sprintf('<select %1$s %2$s name="%3$s"%4$s%5$sdata-placeholder="%6$s"%7$s%8$s>' . PHP_EOL, empty($atts['class']) ? '' : cnHTML::attribute('class', $atts['class']), empty($atts['id']) ? '' : cnHTML::attribute('id', $atts['id']), $atts['type'] == 'multiselect' ? esc_attr($atts['name']) . '[]' : esc_attr($atts['name']), empty($atts['style']) ? '' : cnHTML::attribute('style', $atts['style']), $atts['type'] == 'multiselect' ? '' : (empty($atts['on_change']) ? '' : sprintf(' onchange="%s" ', esc_js($atts['on_change']))), esc_attr($atts['default']), $atts['type'] == 'multiselect' ? ' MULTIPLE' : '', (int) $atts['tab_index'] > 0 ? " tabindex=\"{$atts['tab_index']}\"" : ''); } else { $select .= ''; } if (empty($terms) && !$atts['hide_if_empty'] && !empty($atts['show_option_none'])) { /** This filter is documented in includes/template/class.template-walker-term-select.php */ $show_option_none = apply_filters('cn_list_cats', $atts['show_option_none']); $select .= "\t<option value='" . esc_attr($atts['option_none_value']) . "' selected='selected'>{$show_option_none}</option>" . PHP_EOL; } if (!empty($terms)) { if ($atts['enhanced']) { $select .= "\t" . '<option value=""></option>'; } if ($atts['show_select_all'] && $atts['show_option_all']) { /** This filter is documented in includes/template/class.template-walker-term-select.php */ $show_option_all = apply_filters('cn_list_cats', $atts['show_option_all']); $selected = !$atts['enhanced'] && is_numeric($atts['selected']) && '0' === strval($atts['selected']) ? " selected='selected'" : ''; $select .= "\t<option value='0'{$selected}>{$show_option_all}</option>" . PHP_EOL; } if ($atts['show_option_none']) { /** This filter is documented in includes/template/class.template-walker-term-select.php */ $show_option_none = apply_filters('cn_list_cats', $atts['show_option_none']); $selected = selected($atts['option_none_value'], $atts['selected'], FALSE); $select .= "\t<option value='" . esc_attr($atts['option_none_value']) . "'{$selected}>{$show_option_none}</option>" . PHP_EOL; } if ($atts['hierarchical']) { $depth = $atts['depth']; // Walk the full depth. } else { $depth = -1; // Flat. } $select .= $walker->walk($terms, $depth, $atts); } if (!$atts['hide_if_empty'] || !empty($terms)) { // If an option group was left open, ensure it is closed before closing the select. if ($walker->close_group) { $select .= "\t" . '</optgroup>' . PHP_EOL; $walker->close_group = FALSE; } $select .= "</select>" . PHP_EOL; $replace[] = $select; $out = str_ireplace($search, $replace, $atts['layout']); $out = (empty($atts['before']) ? '' : $atts['before']) . $out . (empty($atts['after']) ? '' : $atts['after']); } /** * Filter the taxonomy drop-down output. * * @since 8.2.4 * * @param string $out HTML output. * @param array $atts Arguments used to build the drop-down. */ $out = apply_filters('cn_dropdown_cats', $out, $atts); if ($atts['return']) { return $out; } echo $out; }
/** * Update the term taxonomy counts of the supplied entry IDs for the supplied taxonmies. * * @access private * @since 8.2.5 * @static * * @param mixed $ids array|string An array or comma separated list of entry IDs. * @param mixed $taxonomy array|string An array of taxonomies or taxonomy to update the term taxonomy count. * * @return array|WP_Error An indexed array of term taxonomy IDs which have had their term count updated. WP_Error on failure. */ public static function updateTermCount($ids, $taxonomy = 'category') { // Check for and convert to an array. $ids = wp_parse_id_list($ids); $result = cnTerm::getRelationships($ids, $taxonomy, array('fields' => 'tt_ids')); if (!empty($result) && !is_wp_error($result)) { cnTerm::updateCount($result, $taxonomy); } cnCache::clear(TRUE, 'transient', "cn_{$taxonomy}"); return $result; }
/** * Helper function to insert a new term. * * @access private * @since 8.5.5 * * @param string $name The term name. * @param string $slug The term slug. * @param string $desc The term description. * @param int $parent The term parent ID. * * @return array|WP_Error An array containing the term_id and term_taxonomy_id, WP_Error otherwise. */ private function insertTerm($name, $slug = '', $desc = '', $parent = 0) { $atts = array('slug' => $slug, 'description' => $desc, 'parent' => $parent); $result = cnTerm::insert($name, $this->type, $atts); if (is_wp_error($result)) { error_log('Term Import Error: ' . $result->get_error_message()); error_log(' - Name: ' . print_r($name, TRUE)); error_log(' - Slug: ' . print_r($slug, TRUE)); error_log(' - Parent ID: ' . print_r($parent, TRUE)); } return $result; }
/** * Display a message box above the search results with information * about the current query and the option (a button) to clear results. * * @access public * @since 0.8 * @static * @param array $atts The shortcode $atts array. * @param array $results The cnRetrieve query results. * @param cnTemplate|null $template An instance of the cnTemplate object. * * @return string */ public static function searchingMessage($atts = array(), $results = array(), $template = NULL) { // Check whether or not the category description should be displayed or not. if (!cnSettingsAPI::get('connections', 'connections_display_results', 'search_message')) { return ''; } $defaults = array('return' => FALSE); $atts = wp_parse_args($atts, $defaults); $out = array(); // Get the directory home page ID. $homeID = $atts['force_home'] ? cnSettingsAPI::get('connections', 'connections_home_page', 'page_id') : $atts['home_id']; //$addAction = cnSettingsAPI::get( 'connections', 'connections_home_page', 'page_id' ) != $atts['home_id'] ? TRUE : FALSE; // The base post permalink is required, do not filter the permalink thru cnSEO. if (!is_admin()) { cnSEO::doFilterPermalink(FALSE); } $permalink = get_permalink($homeID); $permalink = apply_filters('cn_permalink', $permalink, $atts); // Re-enable the filter. if (!is_admin()) { cnSEO::doFilterPermalink(); } // Store the query vars $queryVars = array(); $queryVars['cn-s'] = get_query_var('cn-s') ? esc_html(get_query_var('cn-s')) : FALSE; $queryVars['cn-char'] = get_query_var('cn-char') ? esc_html(urldecode(get_query_var('cn-char'))) : FALSE; $queryVars['cn-cat'] = get_query_var('cn-cat') ? get_query_var('cn-cat') : FALSE; $queryVars['cn-organization'] = get_query_var('cn-organization') ? esc_html(urldecode(get_query_var('cn-organization'))) : FALSE; $queryVars['cn-department'] = get_query_var('cn-department') ? esc_html(urldecode(get_query_var('cn-department'))) : FALSE; $queryVars['cn-locality'] = get_query_var('cn-locality') ? esc_html(urldecode(get_query_var('cn-locality'))) : FALSE; $queryVars['cn-region'] = get_query_var('cn-region') ? esc_html(urldecode(get_query_var('cn-region'))) : FALSE; $queryVars['cn-postal-code'] = get_query_var('cn-postal-code') ? esc_html(urldecode(get_query_var('cn-postal-code'))) : FALSE; $queryVars['cn-country'] = get_query_var('cn-country') ? esc_html(urldecode(get_query_var('cn-country'))) : FALSE; // if ( get_query_var('cn-near-coord') ) $queryVars['cn-near-coord'] = get_query_var('cn-near-coord'); // if ( get_query_var('cn-radius') ) $queryVars['cn-radius'] = get_query_var('cn-radius'); // if ( get_query_var('cn-unit') ) $queryVars['cn-unit'] = get_query_var('cn-unit'); if ($queryVars['cn-cat']) { $categoryID = $queryVars['cn-cat']; $terms = array(); // Since the `cn-cat` query var can be an array, we'll only add the category slug // template name when querying a single category. if (is_array($categoryID)) { foreach ($categoryID as $id) { $term = cnTerm::getBy('id', $id, 'category'); $terms[] = esc_html($term->name); } } else { $term = cnTerm::getBy('id', $categoryID, 'category'); $terms[] = esc_html($term->name); } $out[] = sprintf(__('You are searching within category(ies): %s', 'connections'), implode(', ', $terms)); } if ($queryVars['cn-s']) { // If value is a string, string the white space and covert to an array. if (!is_array($queryVars['cn-s'])) { $queryVars['cn-s'] = explode(' ', trim($queryVars['cn-s'])); } // Trim any white space from around the terms in the array. array_walk($queryVars['cn-s'], 'trim'); $out[] = sprintf(__('You are searching for the keyword(s): %s', 'connections'), implode(', ', $queryVars['cn-s'])); } if ($queryVars['cn-char']) { $out[] = sprintf(__('The results are being filtered by the character: %s', 'connections'), $queryVars['cn-char']); } if ($queryVars['cn-organization']) { $out[] = sprintf(__('The results are being filtered by the organization: %s', 'connections'), $queryVars['cn-organization']); } if ($queryVars['cn-department']) { $out[] = sprintf(__('The results are being filtered by the department: %s', 'connections'), $queryVars['cn-department']); } if ($queryVars['cn-locality']) { $out[] = sprintf(__('The results are being filtered by the locality: %s', 'connections'), $queryVars['cn-locality']); } if ($queryVars['cn-region']) { $out[] = sprintf(__('The results are being filtered by the region: %s', 'connections'), $queryVars['cn-region']); } if ($queryVars['cn-postal-code']) { $out[] = sprintf(__('The results are being filtered by the postal code: %s', 'connections'), $queryVars['cn-postal-code']); } if ($queryVars['cn-country']) { $out[] = sprintf(__('The results are being filtered by the country: %s', 'connections'), $queryVars['cn-country']); } // Convert the search messages in a HTML UL list. if (!empty($out)) { $out = '<li class="cn-search-message">' . implode('</li><li class="cn-search-message">', $out) . '</li>'; $out = '<ul id="cn-search-message-list">' . $out . '</ul>'; $out .= sprintf('<div id="cn-clear-search"><a class="button btn" id="cn-clear-search-button" href="%1$s">%2$s</a></div>', esc_url($permalink), __('Clear Search', 'connections')); $out = '<div id="cn-search-messages">' . $out . '</div>'; } else { $out = ''; } return self::echoOrReturn($atts['return'], $out); }
/** * An indexed array of file names to be searched for. * * The file names is an index array of file names where the * highest priority is first and the lowest priority is last. * * @access private * @since 0.8 * @uses apply_filters() * @uses get_query_var() * @param string $base The base file name. Typically `card` for a template file and the template slug for CSS and JS files. * @param string $name The template part name; such as `single` or `category`. * @param string $slug The template part slug; such as an entry slug or category slug. * @param string $ext [optional] The template file name extension. Defaults to `php`. * * @return array An indexed array of file names to search for. */ private function fileNames($base, $name = NULL, $slug = NULL, $ext = 'php') { $files = array(); if (get_query_var('cn-cat')) { $categoryID = get_query_var('cn-cat'); // Since the `cn-cat` query var can be an array, we'll only add the category slug // template name when querying a single category. if (!is_array($categoryID)) { $term = cnTerm::getBy('id', $categoryID, 'category'); $files[] = $this->fileName($base, 'category', $term->slug, $ext); } $files[] = $this->fileName($base, 'category', NULL, $ext); // var_dump( $files ); } if (get_query_var('cn-cat-slug')) { $files[] = $this->fileName($base, 'category', get_query_var('cn-cat-slug'), $ext); $files[] = $this->fileName($base, 'category', NULL, $ext); // var_dump( $files ); } if (get_query_var('cn-country')) { $country = $this->queryVarSlug(get_query_var('cn-country')); $files[] = $this->fileName($base, 'country', $country, $ext); $files[] = $this->fileName($base, 'country', NULL, $ext); // var_dump( $files ); } if (get_query_var('cn-region')) { $region = $this->queryVarSlug(get_query_var('cn-region')); $files[] = $this->fileName($base, 'region', $region, $ext); $files[] = $this->fileName($base, 'region', NULL, $ext); // var_dump( $files ); } if (get_query_var('cn-postal-code')) { $zipcode = $this->queryVarSlug(get_query_var('cn-postal-code')); $files[] = $this->fileName($base, 'postal-code', $zipcode, $ext); $files[] = $this->fileName($base, 'postal-code', NULL, $ext); // var_dump( $files ); } if (get_query_var('cn-locality')) { $locality = $this->queryVarSlug(get_query_var('cn-locality')); $files[] = $this->fileName($base, 'locality', $locality, $ext); $files[] = $this->fileName($base, 'locality', NULL, $ext); // var_dump( $files ); } if (get_query_var('cn-organization')) { $organization = $this->queryVarSlug(get_query_var('cn-organization')); $files[] = $this->fileName($base, 'organization', $organization, $ext); $files[] = $this->fileName($base, 'organization', NULL, $ext); // var_dump( $files ); } if (get_query_var('cn-department')) { $department = $this->queryVarSlug(get_query_var('cn-department')); $files[] = $this->fileName($base, 'department', $department, $ext); $files[] = $this->fileName($base, 'department', NULL, $ext); // var_dump( $files ); } if (get_query_var('cn-entry-slug')) { $files[] = $this->fileName($base, NULL, get_query_var('cn-entry-slug'), $ext); $files[] = $this->fileName($base, 'single', NULL, $ext); // var_dump( $files ); } // Add the base as the least priority, since it is required. $files[] = $this->fileName($base, NULL, NULL, $ext); /** * Allow template choices to be filtered. * * The resulting array should be in the order of most specific first, least specific last. * e.g. 0 => card-single.php, 1 => card.php */ $files = apply_filters('cn_template_file_names-' . $this->slug, $files, $base, $name, $slug, $ext); // var_dump( $files ); // Sort the files based on priority ksort($files, SORT_NUMERIC); // var_dump( $files ); return array_filter($files); }
/** * The category metabox. * * @access public * @since 0.8 * @param cnEntry $entry An instance of the cnEntry object. * @param array $metabox The metabox options array from self::register(). * @return string The category metabox. */ public static function category($entry, $metabox) { echo '<div class="categorydiv" id="taxonomy-category">'; echo '<div id="category-all" class="tabs-panel">'; cnTemplatePart::walker('term-checklist', array('selected' => cnTerm::getRelationships($entry->getID(), 'category', array('fields' => 'ids')))); echo '</div>'; echo '</div>'; }
/** * 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; }
/** * Display or retrieve the HTML select list of terms. * * This is the Connections equivalent of @see wp_dropdown_categories() in WordPress core ../wp-includes/category-template.php * * @access public * @since 8.2 * @static * * @uses wp_parse_args() * @uses cnTerm::getTaxonomyTerms() * @uses esc_attr() * @uses sanitize_html_class() * @uses apply_filters() * @uses Walker::walk() * @uses selected() * * @param array $atts { * Optional. An array of arguments. * NOTE: Additionally, all valid options as supported in @see cnTerm::getTaxonomyTerms(). * * @type string $show_option_all A non-blank value causes the display of a link to the directory home page. * Default: ''. The default is not to display a link. * Accepts: Any valid string. * @type string $show_option_none Set the text to show when no categories are listed. * Default: 'No Categories' * Accepts: Any valid string. * @type bool $show_count Whether or not to display the category count. * Default: FALSE * @type string $name The select name attribute. * Default: 'cat' * @type string $id The select id attribute. * Default: '' * @type string $class The select class attribute. * Default: 'postform' * @type int $depth Controls how many levels in the hierarchy of categories are to be included in the list. * Default: 0 * Accepts: 0 - All categories and child categories. * -1 - All Categories displayed flat, not showing the parent/child relationships. * 1 - Show only top level/root parent categories. * n - Value of n (int) specifies the depth (or level) to descend in displaying the categories. * @type int $tab_index The select tab index. * Default: 0 * @type string $taxonomy The taxonomy tree to display. * Default: 'category' * Accepts: Any registered taxonomy. * @type bool $hide_if_empty Whether or not to show the select if no terms are returned by term query. * Default: FALSE * @type string $option_none_value Value to use when no term is selected. * Default: -1 * Accepts: Any valid int/string for an option value attribute. * @type int $selected The selected term ID. * @type bool $return Whether or not to return or echo the resulting HTML. * Default: FALSE * } * * @return string */ public static function render($atts = array()) { $out = ''; $defaults = array('show_option_all' => '', 'show_option_none' => '', 'orderby' => 'name', 'order' => 'ASC', 'show_count' => FALSE, 'hide_empty' => FALSE, 'name' => 'cat', 'id' => '', 'class' => 'postform', 'depth' => 0, 'tab_index' => 0, 'taxonomy' => 'category', 'hide_if_empty' => FALSE, 'option_none_value' => -1, 'selected' => 0, 'return' => FALSE); $atts = wp_parse_args($atts, $defaults); $walker = new self(); $walker->tree_type = $atts['taxonomy']; if (!isset($atts['pad_counts']) && $atts['show_count'] && $atts['hierarchical']) { $atts['pad_counts'] = TRUE; } $tab_index_attribute = (int) $atts['tab_index'] > 0 ? " tabindex=\"{$atts['tab_index']}\"" : ''; $terms = cnTerm::getTaxonomyTerms($atts['taxonomy'], $atts); $name = esc_attr($atts['name']); $class = sanitize_html_class($atts['class']); $id = $atts['id'] ? esc_attr($atts['id']) : $name; if (!$atts['hide_if_empty'] || !empty($terms)) { $out .= PHP_EOL . "<select name='{$name}' id='{$id}' class='{$class}' {$tab_index_attribute}>" . PHP_EOL; } else { $out .= ''; } if (empty($terms) && !$atts['hide_if_empty'] && !empty($atts['show_option_none'])) { /** * Filter a taxonomy drop-down display element. * * @since 8.2 * * @param string $element Taxonomy term name. */ $show_option_none = apply_filters('cn_list_cats', $atts['show_option_none']); $out .= "\t<option value='" . esc_attr($atts['option_none_value']) . "' selected='selected'>{$show_option_none}</option>\n"; } if (!empty($terms)) { if ($atts['show_option_all']) { /** This filter is documented in includes/template/class.template-walker-term-select.php */ $show_option_all = apply_filters('cn_list_cats', $atts['show_option_all']); $selected = '0' === strval($atts['selected']) ? " selected='selected'" : ''; $out .= "\t<option value='0'{$selected}>{$show_option_all}</option>\n"; } if ($atts['show_option_none']) { /** This filter is documented in includes/template/class.template-walker-term-select.php */ $show_option_none = apply_filters('cn_list_cats', $atts['show_option_none']); $selected = selected($atts['option_none_value'], $atts['selected'], FALSE); $out .= "\t<option value='" . esc_attr($atts['option_none_value']) . "'{$selected}>{$show_option_none}</option>\n"; } if ($atts['hierarchical']) { $depth = $atts['depth']; // Walk the full depth. } else { $depth = -1; // Flat. } $out .= $walker->walk($terms, $depth, $atts); } if (!$atts['hide_if_empty'] || !empty($terms)) { $out .= "</select>" . PHP_EOL; } /** * Filter the taxonomy drop-down output. * * @since 8.2 * * @param string $out HTML output. * @param array $atts Arguments used to build the drop-down. */ $out = apply_filters('cn_dropdown_cats', $out, $atts); if ($atts['return']) { return $out; } echo $out; }
/** * Returns the current category being viewed. * * @access public * @since 8.5.18 * @static * * @return false|cnTerm_Object */ public static function getCurrent() { $current = FALSE; if (cnQuery::getVar('cn-cat-slug')) { $slug = explode('/', cnQuery::getVar('cn-cat-slug')); // If the category slug is a descendant, use the last slug from the URL for the query. $current = end($slug); } elseif ($catIDs = cnQuery::getVar('cn-cat')) { if (is_array($catIDs)) { // If value is a string, strip the white space and covert to an array. $catIDs = wp_parse_id_list($catIDs); // Use the first element $current = reset($catIDs); } else { $current = $catIDs; } } if (!empty($current)) { if (ctype_digit((string) $current)) { $field = 'id'; } else { $field = 'slug'; } $current = cnTerm::getBy($field, $current, 'category'); // cnTerm::getBy() can return NULL || an instance of WP_Error, so, lets check for that. if (!is_a($current, 'cnTerm_Object')) { $current = FALSE; } } return $current; }
/** * 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: ' » ' * @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' => ' » ', '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); }