'',
'before_title' => '',
'after_title' => '',
'after_widget' => '',
]
);
$instance = wp_parse_args(
$instance,
[
'title' => '',
]
);
$feature = Features::factory()->get_registered_feature( 'facets' );
if ( $wp_query->get( 'ep_facet', false ) && ! $feature->is_facetable( $wp_query ) ) {
return false;
}
$es_success = ( ! empty( $wp_query->elasticsearch_success ) ) ? true : false;
if ( ! $es_success ) {
return;
}
if ( empty( $instance['facet'] ) ) {
return;
}
$taxonomy = $instance['facet'];
if ( ! is_search() ) {
$post_type = $wp_query->get( 'post_type' );
if ( empty( $post_type ) ) {
$post_type = 'post';
}
if ( ! is_object_in_taxonomy( $post_type, $taxonomy ) ) {
return;
}
}
$selected_filters = $feature->get_selected();
$match_type = ( ! empty( $instance['match_type'] ) ) ? $instance['match_type'] : 'all';
/**
* Get all the terms so we know if we should output the widget
*/
$terms = get_terms(
/**
* Filter arguments passed to get_terms() while getting all possible terms for the facet widget.
*
* @since 3.5.0
* @hook ep_facet_search_get_terms_args
* @param {array} $query Weighting query
* @param {string} $post_type Post type
* @param {array} $args WP Query arguments
* @return {array} New query
*/
apply_filters(
'ep_facet_search_get_terms_args',
[
'taxonomy' => $taxonomy,
'hide_empty' => true,
],
$args,
$instance
)
);
/**
* Terms validity check
*/
if ( is_wp_error( $terms ) || empty( $terms ) ) {
return;
}
$terms_by_slug = array();
foreach ( $terms as $term ) {
$terms_by_slug[ $term->slug ] = $term;
if ( ! empty( $GLOBALS['ep_facet_aggs'][ $taxonomy ][ $term->slug ] ) ) {
$term->count = $GLOBALS['ep_facet_aggs'][ $taxonomy ][ $term->slug ];
} else {
$term->count = 0;
}
}
/**
* Check to make sure all terms exist before proceeding
*/
if ( ! empty( $selected_filters['taxonomies'][ $taxonomy ] ) && ! empty( $selected_filters['taxonomies'][ $taxonomy ]['terms'] ) ) {
foreach ( $selected_filters['taxonomies'][ $taxonomy ]['terms'] as $term_slug => $nothing ) {
if ( empty( $terms_by_slug[ $term_slug ] ) ) {
/**
* Term does not exist!
*/
return;
}
}
}
$orderby = isset( $instance['orderby'] ) ? $instance['orderby'] : 'count';
$order = isset( $instance['order'] ) ? $instance['order'] : 'count';
$terms = Utils\get_term_tree( $terms, $orderby, $order, true );
$outputted_terms = array();
echo wp_kses_post( $args['before_widget'] );
if ( ! empty( $instance['title'] ) ) {
echo wp_kses_post( $args['before_title'] . apply_filters( 'widget_title', $instance['title'] ) . $args['after_title'] );
}
$taxonomy_object = get_taxonomy( $taxonomy );
/**
* Filter facet search threshold
*
* @hook ep_facet_search_threshold
* @param {int} $search_threshold Search threshold
* @param {string} $taxonomy Current taxonomy
* @return {int} New threshold
*/
$search_threshold = apply_filters( 'ep_facet_search_threshold', 15, $taxonomy );
?>
$search_threshold ) : ?>
$value ) :
if ( ! empty( $outputted_terms[ $term_slug ] ) ) {
continue;
}
$term = $terms_by_slug[ $term_slug ];
if ( empty( $term->parent ) && empty( $term->children ) ) {
$outputted_terms[ $term_slug ] = $term;
$new_filters = $selected_filters;
if ( ! empty( $new_filters['taxonomies'][ $taxonomy ] ) && ! empty( $new_filters['taxonomies'][ $taxonomy ]['terms'][ $term_slug ] ) ) {
unset( $new_filters['taxonomies'][ $taxonomy ]['terms'][ $term_slug ] );
}
// phpcs:disable WordPress.Security.EscapeOutput.OutputNotEscaped
echo $this->get_facet_term_html(
$term,
$feature->build_query_url( $new_filters ),
true
);
// phpcs:enable WordPress.Security.EscapeOutput.OutputNotEscaped
} else {
/**
* This code is so that when we encounter a selected child/parent term, we push it's whole branch
* to the top. Very very painful.
*/
$top_of_tree = $term;
$i = 0;
/**
* Get top of tree
*/
while ( true && $i < 10 ) {
if ( ! empty( $term->parent_slug ) ) {
$top_of_tree = $terms_by_slug[ $term->parent_slug ];
} else {
break;
}
$i++;
}
$flat_ordered_terms = array();
$flat_ordered_terms[] = $top_of_tree;
$to_process = $this->order_by_selected( $top_of_tree->children, $selected_filters['taxonomies'][ $taxonomy ]['terms'], $order, $orderby );
while ( ! empty( $to_process ) ) {
$term = array_shift( $to_process );
$flat_ordered_terms[] = $term;
if ( ! empty( $term->children ) ) {
$to_process = array_merge( $this->order_by_selected( $term->children, $selected_filters['taxonomies'][ $taxonomy ]['terms'], $order, $orderby ), $to_process );
}
}
foreach ( $flat_ordered_terms as $term ) {
$selected = ! empty( $selected_filters['taxonomies'][ $taxonomy ]['terms'][ $term->slug ] );
$outputted_terms[ $term->slug ] = $term;
$new_filters = $selected_filters;
if ( $selected ) {
if ( ! empty( $new_filters['taxonomies'][ $taxonomy ] ) && ! empty( $new_filters['taxonomies'][ $taxonomy ]['terms'][ $term->slug ] ) ) {
unset( $new_filters['taxonomies'][ $taxonomy ]['terms'][ $term->slug ] );
}
} else {
if ( empty( $new_filters['taxonomies'][ $taxonomy ] ) ) {
$new_filters['taxonomies'][ $taxonomy ] = array(
'terms' => array(),
);
}
$new_filters['taxonomies'][ $taxonomy ]['terms'][ $term->slug ] = true;
}
// phpcs:disable WordPress.Security.EscapeOutput.OutputNotEscaped
echo $this->get_facet_term_html(
$term,
$feature->build_query_url( $new_filters ),
$selected
);
// phpcs:enable WordPress.Security.EscapeOutput.OutputNotEscaped
}
}
endforeach;
?>
slug ] ) ) {
continue;
}
$new_filters = $selected_filters;
if ( empty( $new_filters['taxonomies'][ $taxonomy ] ) ) {
$new_filters['taxonomies'][ $taxonomy ] = array(
'terms' => array(),
);
}
$new_filters['taxonomies'][ $taxonomy ]['terms'][ $term->slug ] = true;
// phpcs:disable WordPress.Security.EscapeOutput.OutputNotEscaped
echo $this->get_facet_term_html(
$term,
$feature->build_query_url( $new_filters )
);
// phpcs:enable WordPress.Security.EscapeOutput.OutputNotEscaped
endforeach;
?>
name, $term, $selected );
/**
* Filter the accessible label for an individual facet term link.
*
* Used as the aria-label attribute for filter links. The accessible
* label should include additional context around what action will be
* performed by visiting the link, such as whether the filter will be
* added or removed.
*
* @since 4.0.0
* @hook ep_facet_widget_term_accessible_label
* @param {string} $label Facet term accessible label.
* @param {WP_Term} $term Term object.
* @param {boolean} $selected Whether the term is selected.
* @return {string} Individual facet term accessible label.
*/
$accessible_label = apply_filters(
'ep_facet_widget_term_accessible_label',
$selected
/* translators: %s: Filter term name. */
? sprintf( __( 'Remove filter: %s', 'elasticpress' ), $term->name )
/* translators: %s: Filter term name. */
: sprintf( __( 'Apply filter: %s', 'elasticpress' ), $term->name ),
$term,
$selected
);
$link = sprintf(
'%4$s',
esc_attr( $accessible_label ),
$term->count ? $href : 'aria-role="link" aria-disabled="true"',
$selected ? 'checked' : '',
wp_kses_post( $label )
);
$html = sprintf(
'%6$s
',
absint( $term->level ),
$selected ? 'selected' : '',
! $term->count ? 'empty-term' : '',
esc_attr( strtolower( $term->name ) ),
esc_attr( strtolower( $term->slug ) ),
$link
);
/**
* Filter the HTML for an individual facet term.
*
* For term search to work correctly the outermost wrapper of the term
* HTML must have data-term-name and data-term-slug attributes set to
* lowercase versions of the term name and slug respectively.
*
* @since 3.6.3
* @hook ep_facet_widget_term_html
* @param {string} $html Facet term HTML.
* @param {WP_Term} $term Term object.
* @param {string} $url Filter URL.
* @param {boolean} $selected Whether the term is selected.
* @return {string} Individual facet term HTML.
*/
return apply_filters( 'ep_facet_widget_term_html', $html, $term, $url, $selected );
}
/**
* Order terms putting selected at the top
*
* @param array $terms Array of terms
* @param array $selected_terms Selected terms
* @param string $order The order to sort from. Desc or Asc.
* @param string $orderby The orderby to sort items from.
* @return array
*/
private function order_by_selected( $terms, $selected_terms, $order = false, $orderby = false ) {
$ordered_terms = [];
$terms_by_slug = [];
foreach ( $terms as $term ) {
$terms_by_slug[ $term->slug ] = $term;
}
foreach ( $selected_terms as $term_slug ) {
if ( ! empty( $terms_by_slug[ $term_slug ] ) ) {
$ordered_terms[ $term_slug ] = $terms_by_slug[ $term_slug ];
}
}
foreach ( $terms_by_slug as $term_slug => $term ) {
if ( empty( $ordered_terms[ $term_slug ] ) ) {
$ordered_terms[ $term_slug ] = $terms_by_slug[ $term_slug ];
}
}
if ( 'count' === $orderby ) {
if ( 'asc' === $order ) {
uasort(
$ordered_terms,
function( $a, $b ) {
return $a->count > $b->count;
}
);
} else {
uasort(
$ordered_terms,
function( $a, $b ) {
return $a->count < $b->count;
}
);
}
} else {
if ( 'asc' === $order ) {
ksort( $ordered_terms );
} else {
krsort( $ordered_terms );
}
}
return array_values( $ordered_terms );
}
}