'parent', 'id' => 'term_id', ); public $max_depth = 0; public $has_not_empty_children = []; public $parent_opened_elements = []; /** * Starts the list before the elements are added. * * @since 2.1.0 * * @see Walker::start_lvl() * * @param string $output Used to append additional content. Passed by reference. * @param int $depth Optional. Depth of category. Used for tab indentation. Default 0. * @param array $args Optional. An array of arguments. Will only append content if style argument * value is 'list'. See wp_list_categories(). Default empty array. */ public function start_lvl( &$output, $depth = 0, $args = array() ) { $indent = str_repeat( "\t", $depth ); $output .= "$indent\n"; } /** * Starts the element output. * * @since 2.1.0 * * @see Walker::start_el() * * @param string $output Used to append additional content (passed by reference). * @param WP_Term $term Term data object. * @param int $depth Optional. Depth of category in reference to parents. Default 0. * @param array $args Optional. An array of arguments. See wp_list_categories(). Default empty array. * @param int $id Optional. ID of the current category. Default 0. */ public function start_el( &$output, $term, $depth = 0, $args = array(), $id = 0 ) { $term_name = esc_attr( $term->name ); $url_manager = $args['url_manager']; $filter = $args['filter']; $checked = ( in_array( $term->slug, $filter['values'] ) ) ? 1 : 0; $disabled = 0; if( isset( $term->wp_queried ) && $term->wp_queried ){ $checked = 1; $disabled = 1; } $id = $id ? $id : $term->term_id; $toggleButton = ''; $visibility_class = ''; // Don't generate an element if the term name is empty. if ( '' === $term_name ) { return; } $atts = array(); $atts['href'] = flrt_get_filtered_term_url($term, $filter, $url_manager); $atts['class'] = 'wpc-filter-link'; $attributes = ''; foreach ( $atts as $attr => $value ) { if ( is_scalar( $value ) && '' !== $value && false !== $value ) { $value = ( 'href' === $attr ) ? esc_url( $value ) : esc_attr( $value ); $attributes .= ' ' . $attr . '="' . $value . '"'; } } $link = apply_filters( 'wpc_filters_checkbox_term_html', ''.$term->name.'', $attributes, $term, $filter ); if ( isset( $args['set']['show_count']['value'] ) && $args['set']['show_count']['value'] === 'yes' ) { $link .= flrt_filter_get_count( $term ); } $is_hide_empty_terms = (isset($args['set']['hide_empty']['value']) && $args['set']['hide_empty']['value'] === 'yes'); $hide_for_apply_button_mode = flrt_check_apply_buttom_mode($args['set']); $show_with_parent_class = ''; $isShowWithParentClass = false; if(isset($term->show_with_parent)) { if($term->show_with_parent === true){ $isShowWithParentClass = true; $show_with_parent_class = 'wpc-show-with-parent-true'; }else{ $show_with_parent_class = 'wpc-show-with-parent-false'; } } if (!isset($term->show_with_parent)) { if ($args['ask_to_select_parent'] !== false && $args['use_apply_button']) { if ((!$checked)) { $show_with_parent_class = 'wpc-show-with-parent-false'; } } } $hidden_class_for_apply_button_mode = ''; $more_less_hidden_class = ''; if ($args['isMoreLess']) { if (!empty($term->apply_button_style) && $term->apply_button_style === true) { $more_less_hidden_class = 'wpc-not-hidden-term'; } } if($hide_for_apply_button_mode){ $hidden_class_for_apply_button_mode = ($term->cross_count <= 0 && $is_hide_empty_terms) ? esc_attr(' wpc-term-count-hidden-0') : ''; if($checked){ $hidden_class_for_apply_button_mode .= esc_attr('wpc-term-count-hidden-checked-0'); } } $output .= "\tcross_count ) ? esc_attr( $term->cross_count ) : ''; $css_classes = array( 0 => 'wpc-checkbox-item', 1 => 'wpc-term-item', 3 => 'wpc-term-count-' . $cross_count, 4 => 'wpc-term-id-'.$id, 5 => $hidden_class_for_apply_button_mode, 6 => $more_less_hidden_class, 7 => esc_attr($show_with_parent_class), ); if( $this->max_depth > 0 ) { $visibility_class = flrt_get_status_css_class( $id, FLRT_HIERARCHY_LIST_COOKIE_NAME ); // If has already saved visibility class if ( $visibility_class === '' ) { // If there is no saved visibility class $parent_opened_elements_flipped = array_flip( $this->parent_opened_elements ); if ( isset( $parent_opened_elements_flipped[$id] ) ) { $visibility_class = 'wpc-opened'; } if ( $this->has_children && $checked && $visibility_class === '' ) { $visibility_class = 'wpc-opened'; } } $css_classes[] = $visibility_class; } if( $checked ){ $css_classes[2] = 'wpc-term-selected'; } if( $disabled ){ $css_classes[] = 'wpc-term-disabled'; } if( $this->has_children ){ $css_classes[] = 'wpc-has-children'; $toggleButton = ''; } $has_not_empty_children_flipped = array_flip( $this->has_not_empty_children ); if( isset( $has_not_empty_children_flipped[$id] ) ){ $css_classes[] = 'wpc-has-not-empty-children'; } $css_classes = implode( ' ', $css_classes ); $css_classes = $css_classes ? ' class="' . esc_attr( $css_classes ) . '"' : ''; $rating_slugs = flrt_rating_slugs(); $rating_data = (isset($rating_slugs[$term->slug])) ? ' data-rating-num="' . esc_attr($rating_slugs[$term->slug]) . '" ' : ''; $output .= $css_classes; $output .= ' id="'.flrt_term_id('term', $filter, $id, false).'">'; $output .= '
'."\n"; $output .= '\n"; $output .= $toggleButton; $output .= "
\n"; } /** * Ends the element output, if needed. * * @since 2.1.0 * * @see Walker::end_el() * * @param string $output Used to append additional content (passed by reference). * @param object $page Not used. * @param int $depth Optional. Depth of category. Not used. * @param array $args Optional. An array of arguments. Only uses 'list' for whether should append * to output. See wp_list_categories(). Default empty array. */ public function end_el( &$output, $page, $depth = 0, $args = array() ) { $output .= "\n"; } public function walk( $elements, $max_depth, ...$args ) { $output = ''; $this->max_depth = $max_depth; // Invalid parameter or nothing to walk. if ( $max_depth < -1 || empty( $elements ) ) { return $output; } $parent_field = $this->db_fields['parent']; // Flat display. $flrt_more_less_count = flrt_more_less_count(); $isParentFilter = flrtParentFilter($args[0]['filter']); $hidden_terms_count = 1; if ( -1 == $max_depth ) { $empty_array = array(); foreach ( $elements as $e ) { if ( $args[0]['isMoreLess'] ) { $is_visible = !$isParentFilter || ( isset( $e->show_with_parent ) && $e->show_with_parent === true ) || !isset( $e->show_with_parent ); $has_results = !$args[0]['is_hide_empty_terms'] || $e->cross_count > 0; if ( $is_visible && $has_results ) { if ( $hidden_terms_count <= $flrt_more_less_count ) { $e->apply_button_style = true; } $hidden_terms_count++; } } $this->display_element( $e, $empty_array, 1, 0, $args, $output ); } return $output; } /* * Need to display in hierarchical order. * Separate elements into two buckets: top level and children elements. * Children_elements is two dimensional array, eg. * Children_elements[10][] contains all sub-elements whose parent is 10. */ $top_level_elements = array(); $children_elements = array(); $parent_opened_elements = array(); foreach ( $elements as $e ) { if ( empty( $e->$parent_field ) ) { $top_level_elements[] = $e; } else { $children_elements[ $e->$parent_field ][] = $e; } if( ! empty( $args[0]['filter']['values'] ) ){ if( in_array( $e->slug, $args[0]['filter']['values'] ) ){ $parent_opened_elements[] = $e->$parent_field; flrt_get_all_parents( $elements, $e->$parent_field, $parent_opened_elements ); } } } $this->parent_opened_elements = array_unique($parent_opened_elements); $this->has_not_empty_children = flrt_get_parents_with_not_empty_children($elements); /* * When none of the elements is top level. * Assume the first one must be root of the sub elements. */ if ( empty( $top_level_elements ) ) { $first = array_slice( $elements, 0, 1 ); $root = $first[0]; $top_level_elements = array(); $children_elements = array(); foreach ( $elements as $e ) { if ( $root->$parent_field == $e->$parent_field ) { $top_level_elements[] = $e; } else { $children_elements[ $e->$parent_field ][] = $e; } } } /* * Same More/Less marking as in the flat branch above. Only top-level terms * are counted: the reveal CSS (.wpc-filters-ul-list > li.wpc-not-hidden-term) * targets direct children of the list, nested children follow their parent. * Without this, a hierarchical More/Less list renders with all terms hidden * until JS re-marks them. */ if ( $args[0]['isMoreLess'] ) { $has_not_empty_children_flipped = array_flip( $this->has_not_empty_children ); foreach ( $top_level_elements as $e ) { $is_visible = !$isParentFilter || ( isset( $e->show_with_parent ) && $e->show_with_parent === true ) || !isset( $e->show_with_parent ); $has_results = !$args[0]['is_hide_empty_terms'] || $e->cross_count > 0 || isset( $has_not_empty_children_flipped[ $e->term_id ] ); if ( $is_visible && $has_results ) { if ( $hidden_terms_count <= $flrt_more_less_count ) { $e->apply_button_style = true; } $hidden_terms_count++; } } } foreach ( $top_level_elements as $e ) { $this->display_element( $e, $children_elements, $max_depth, 0, $args, $output ); } /* * If we are displaying all levels, and remaining children_elements is not empty, * then we got orphans, which should be displayed regardless. */ if ( ( 0 == $max_depth ) && count( $children_elements ) > 0 ) { $empty_array = array(); foreach ( $children_elements as $orphans ) { foreach ( $orphans as $op ) { $this->display_element( $op, $empty_array, 1, 0, $args, $output ); } } } return $output; } }