/** * Get the data being exported. * * @access public * @since 8.5.5 * * @return array $data Data for Export */ public function getData() { /** @var wpdb $wpdb */ //global $wpdb; $data = array(); $offset = $this->limit * ($this->step - 1); $results = cnTerm::getTaxonomyTerms($this->type, array('hide_empty' => FALSE, 'hierarchical' => FALSE, 'offset' => $offset, 'number' => $this->limit)); $count = cnTerm::getTaxonomyTerms($this->type, array('hide_empty' => FALSE, 'fields' => 'count')); $this->setCount($count); $i = 0; $terms = $this->buildHierarchy($results); foreach ($terms as $term) { $data[$i]['id'] = $term->term_id; $data[$i]['name'] = $term->name; $data[$i]['desc'] = $term->description; $data[$i]['slug'] = $term->slug; $data[$i]['hierarchy'] = $term->hierarchy; $i++; } $data = apply_filters('cn_export_get_data', $data); $data = apply_filters('cn_export_get_data_' . $this->type, $data); return $data; }
/** * 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; }
/** * Prepares the list of items for displaying. * * @access public * @since 8.2 * * @uses WP_List_Table::get_items_per_page() * @uses WP_List_Table::get_pagenum() * @uses WP_List_Table::set_pagination_args() * @uses apply_filters() * @uses wp_unslash() * @uses cnTerm::getTaxonomyTerms() * @uses CN_Term_Admin_List_Table::get_columns() * @uses CN_Term_Admin_List_Table::get_hidden_columns() * @uses CN_Term_Admin_List_Table::get_sortable_columns() */ public function prepare_items() { // @todo this should be a screen option. $per_page = $this->get_items_per_page("cn_edit_{$this->taxonomy}_per_page", 100); /** * Filter the number of terms displayed per page for the terms list table. * * @since 8.2 * * @param int $per_page Number of terms to be displayed. */ $per_page = apply_filters("cn_edit_{$this->taxonomy}_per_page", $per_page); /** * NOTE: * Several of the $args vars are required in other parts of the class * which is why they are also assigned to class vars as well as the local * $args array var. */ $this->search = !empty($_REQUEST['s']) ? trim(wp_unslash($_REQUEST['s'])) : ''; $args = array('page' => $this->get_pagenum(), 'number' => $per_page, 'hide_empty' => FALSE, 'search' => $this->search); if (!empty($_REQUEST['orderby'])) { $args['orderby'] = $this->orderby = trim(wp_unslash($_REQUEST['orderby'])); } if (!empty($_REQUEST['order'])) { $args['order'] = trim(wp_unslash($_REQUEST['order'])); } // Set variable because $args['number'] can be subsequently overridden if doing an orderby term query. $this->number = $args['number']; $args['offset'] = $this->offset = ($args['page'] - 1) * $args['number']; // Query the all of terms. if (is_null($this->orderby)) { $args['number'] = $args['offset'] = 0; } $this->items = cnTerm::getTaxonomyTerms($this->taxonomy, $args); $this->set_pagination_args(array('total_items' => cnTerm::getTaxonomyTerms($this->taxonomy, array('hide_empty' => FALSE, 'search' => $this->search, 'fields' => 'count')), 'per_page' => $per_page)); /** * NOTE: If these methods are overridden @see WP_List_Table::get_column_info(), * then the column filter in @see get_column_headers() is not run. * * As a workaround filters are added to the following methods. The downside * is that the screen options to hide columns are not added. The only way for that * to happen seems to be to init the table class on the `load-{page-hook}` action * and set it as a global var so it can be accessed in the callback function that * renders the plugin's admin page. */ $columns = $this->get_columns(); $hidden = $this->get_hidden_columns(); $sortable = $this->get_sortable_columns(); $this->_column_headers = array($columns, $hidden, $sortable); }
/** * 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; }
/** * 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. }
/** * Get a collection of items * * @since 8.5.26 * * @param WP_REST_Request $request Full data about the request. * * @return WP_Error|WP_REST_Response */ public function get_items($request) { $prepared_args = array('exclude' => $request['exclude'], 'include' => $request['include'], 'order' => $request['order'], 'orderby' => $request['orderby'], 'post' => $request['post'], 'hide_empty' => $request['hide_empty'], 'number' => $request['per_page'], 'search' => $request['search'], 'slug' => $request['slug']); if (!empty($request['offset'])) { $prepared_args['offset'] = $request['offset']; } else { $prepared_args['offset'] = ($request['page'] - 1) * $prepared_args['number']; } //$taxonomy_obj = get_taxonomy( $this->taxonomy ); //if ( $taxonomy_obj->hierarchical && isset( $request['parent'] ) ) { if (0 === $request['parent']) { // Only query top-level terms. $prepared_args['parent'] = 0; } else { if ($request['parent']) { $prepared_args['parent'] = $request['parent']; } } //} /** * Filter the query arguments, before passing them to `cnTerm::getTaxonomyTerms()`. * * Enables adding extra arguments or setting defaults for a terms * collection request. * * @since 8.5.26 * * @param array $prepared_args Array of arguments to be * passed to get_terms. * @param WP_REST_Request $request The current request. */ $prepared_args = apply_filters("cn_rest_{$this->taxonomy}_query", $prepared_args, $request); if (!empty($prepared_args['post'])) { $query_result = $this->get_terms_for_post($prepared_args); $total_terms = $this->total_terms; } else { $query_result = cnTerm::getTaxonomyTerms($this->taxonomy, $prepared_args); $count_args = $prepared_args; unset($count_args['number']); unset($count_args['offset']); $count_args['hide_empty'] = FALSE; $count_args['fields'] = 'count'; $total_terms = cnTerm::getTaxonomyTerms($this->taxonomy, $count_args); // Ensure we don't return results when offset is out of bounds // see https://core.trac.wordpress.org/ticket/35935 if ($prepared_args['offset'] >= $total_terms) { $query_result = array(); } // $total_terms can be a falsy value when the term has no children if (!$total_terms) { $total_terms = 0; } } $response = array(); foreach ($query_result as $term) { $data = $this->prepare_item_for_response($term, $request); $response[] = $this->prepare_response_for_collection($data); } $response = rest_ensure_response($response); // Store pagination values for headers then unset for count query. $per_page = (int) $prepared_args['number']; $page = ceil((int) $prepared_args['offset'] / $per_page + 1); $response->header('X-WP-Total', (int) $total_terms); $max_pages = ceil($total_terms / $per_page); $response->header('X-WP-TotalPages', (int) $max_pages); $base = add_query_arg($request->get_query_params(), rest_url($this->namespace . '/' . $this->rest_base)); if ($page > 1) { $prev_page = $page - 1; if ($prev_page > $max_pages) { $prev_page = $max_pages; } $prev_link = add_query_arg('page', $prev_page, $base); $response->link_header('prev', $prev_link); } if ($max_pages > $page) { $next_page = $page + 1; $next_link = add_query_arg('page', $next_page, $base); $response->link_header('next', $next_link); } return $response; }
/** * 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; }
/** * 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; }
/** * Render an unordered list of categories. * * This is the Connections equivalent of @see wp_list_categories() in WordPress core ../wp-includes/category-template.php * * @access public * @since 8.1.6 * @static * * @uses wp_parse_args() * @uses cnTerm::getTaxonomyTerms() * @uses cnURL::permalink() * @uses Walker::walk() * * @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 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 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' => __('No categories', 'connections'), 'orderby' => 'name', 'order' => 'ASC', 'show_count' => FALSE, 'hide_empty' => FALSE, 'child_of' => 0, 'exclude' => array(), 'hierarchical' => TRUE, 'depth' => 0, 'parent_id' => array(), 'taxonomy' => 'category', 'return' => FALSE); $atts = wp_parse_args($atts, $defaults); $atts['parent_id'] = wp_parse_id_list($atts['parent_id']); $walker = new self(); if (empty($atts['parent_id'])) { $terms = cnTerm::getTaxonomyTerms($atts['taxonomy'], $atts); } else { $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); } } } $out .= '<ul class="cn-cat-tree">' . PHP_EOL; if (empty($terms)) { $out .= '<li class="cat-item-none">' . $atts['show_option_none'] . '</li>'; } else { if (get_query_var('cn-cat-slug')) { $slug = explode('/', get_query_var('cn-cat-slug')); // If the category slug is a descendant, use the last slug from the URL for the query. $atts['current_category'] = end($slug); } elseif ($catIDs = get_query_var('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 $atts['current_category'] = reset($catIDs); } else { $atts['current_category'] = $catIDs; } } else { $atts['current_category'] = 0; } if (!empty($atts['show_option_all'])) { $out .= '<li class="cat-item-all"><a href="' . cnURL::permalink(array('type' => 'home', 'data' => 'url', 'return' => TRUE)) . '">' . $atts['show_option_all'] . '</a></li>'; } $out .= $walker->walk($terms, $atts['depth'], $atts); } $out .= '</ul>' . PHP_EOL; if ($atts['return']) { return $out; } echo $out; }
/** * 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; }