Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move taxonomy facets to a separate class #2919

Merged
merged 27 commits into from
Aug 25, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
ef1eb9c
Move taxonomy facets to a separate class
felipeelia Aug 1, 2022
5d2c9e0
Move tests and mark as deprecated
felipeelia Aug 3, 2022
9f76ded
Merge branch 'develop' into feature/facet-types
felipeelia Aug 3, 2022
af83a5b
Add tests for the ep_facet_query_string and ep_facet_filter_name filters
felipeelia Aug 3, 2022
0be59c9
Merge remote-tracking branch 'origin/feature/facet-types' into featur…
felipeelia Aug 3, 2022
d623bcd
Only unset args if they are set
felipeelia Aug 3, 2022
f1f6285
set_agg_filters refactor + some tests
felipeelia Aug 3, 2022
cfe2fc7
sanitize GET content before using it
felipeelia Aug 3, 2022
b2a4813
Merge branch 'develop' into feature/facet-types
felipeelia Aug 8, 2022
ef9e8dc
Move some things around
felipeelia Aug 8, 2022
3ada04a
Merge branch 'develop' into feature/facet-types
felipeelia Aug 10, 2022
e6cba8c
Merge branch 'develop' into feature/facet-types
felipeelia Aug 15, 2022
a73405d
Move the new transforms.js file to the right place
felipeelia Aug 15, 2022
4b4fc21
Move some tests back
felipeelia Aug 15, 2022
8e24815
Adjust block name
felipeelia Aug 16, 2022
69a4106
Make sure we only search after indexing
felipeelia Aug 16, 2022
a806f32
More adjustments + better docs
felipeelia Aug 16, 2022
7bc3688
Move some tests around
felipeelia Aug 16, 2022
176276e
Moving more tests
felipeelia Aug 16, 2022
dbb2fdb
Merge branch 'develop' into feature/facet-types
felipeelia Aug 17, 2022
08d6f60
Fix and add tests
felipeelia Aug 17, 2022
94cb4f5
An abstract class just to keep it organized
felipeelia Aug 17, 2022
e451097
Merge branch 'develop' into feature/facet-types
felipeelia Aug 24, 2022
727651e
Move renderer creation so we can pass more info to the ep_facet_rende…
felipeelia Aug 24, 2022
ef182b3
Merge branch 'develop' into feature/facet-types
felipeelia Aug 25, 2022
54a7219
Use get_facetable_taxonomies more often + move ep_facet_use_field so …
felipeelia Aug 25, 2022
c313c4a
Some phpunit tests to check filters usage
felipeelia Aug 25, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
More adjustments + better docs
  • Loading branch information
felipeelia committed Aug 16, 2022
commit a806f327c9d78dcc169ebc58e54ae25888fa8a72
120 changes: 86 additions & 34 deletions includes/classes/Feature/Facets/Facets.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
use ElasticPress\Feature as Feature;
use ElasticPress\Features as Features;
use ElasticPress\Utils as Utils;
use ElasticPress\FeatureRequirementsStatus as FeatureRequirementsStatus;
use ElasticPress\Indexables as Indexables;

if ( ! defined( 'ABSPATH' ) ) {
Expand Down Expand Up @@ -54,6 +53,26 @@ public function __construct() {
'taxonomy' => __NAMESPACE__ . '\Types\Taxonomy\FacetType',
];

/**
* Filter the Facet types available.
*
* ```
* add_filter(
* 'ep_facet_types',
* function ( $types ) {
* $types['post_type'] = '\MyPlugin\PostType';
* return $types;
* }
* );
* ```
*
* @since 4.3.0
* @hook ep_facet_types
* @param {array} $types Array of types available. Keys are slugs, values are class names.
* @return {array} New array of types available
*/
$types = apply_filters( 'ep_facet_types', $types );

foreach ( $types as $type => $class ) {
$this->types[ $type ] = new $class();
}
Expand Down Expand Up @@ -113,7 +132,10 @@ public function output_feature_box_settings() {
}

/**
* If we are doing or matches, we need to remove filters from aggs
* If we are doing `or` matches, we need to remove filters from aggs.
*
* By default, the same filters applied to the main query are applied to aggregations.
* If doing `or` matches, those should be removed so we get a broader set of results.
*
* @param array $args ES arguments
* @param array $query_args Query arguments
Expand All @@ -127,43 +149,30 @@ public function set_agg_filters( $args, $query_args, $query ) {
return $args;
}

// Without taxonomies there is nothing to do here.
if ( empty( $query_args['tax_query'] ) ) {
return $args;
}

$feature = Features::factory()->get_registered_feature( 'facets' );
$settings = wp_parse_args(
$feature->get_settings(),
array(
'match_type' => 'all',
)
);

$facet_query_args = $query_args;

if ( 'any' === $settings['match_type'] ) {
foreach ( $facet_query_args['tax_query'] as $key => $taxonomy ) {
if ( is_array( $taxonomy ) ) {
unset( $facet_query_args['tax_query'][ $key ] );
}
}
}

// @todo For some reason these are appearing in the query args, need to investigate
$unwanted_args = [ 'category_name', 'cat', 'tag', 'tag_id', 'taxonomy', 'term' ];
foreach ( $unwanted_args as $unwanted_arg ) {
unset( $facet_query_args[ $unwanted_arg ] );
}
/**
* Filter WP query arguments that will be used to build the aggregations filter.
*
* The returned `$query_args` will be used to build the aggregations filter passing
* it through `Indexable\Post\Post::format_args()`.
*
* @hook ep_facet_agg_filters
* @since 4.3.0
* @param {array} $query_args Query arguments
* @param {array} $args ES arguments
* @param {array} $query WP Query instance
* @return {array} New facets aggregations
*/
$query_args = apply_filters( 'ep_facet_agg_filters', $query_args, $args, $query );

remove_filter( 'ep_post_formatted_args', [ $this, 'set_agg_filters' ], 10, 3 );
$facet_formatted_args = Indexables::factory()->get( 'post' )->format_args( $facet_query_args, $query );
$facet_formatted_args = Indexables::factory()->get( 'post' )->format_args( $query_args, $query );
add_filter( 'ep_post_formatted_args', [ $this, 'set_agg_filters' ], 10, 3 );

$args['aggs']['terms']['filter'] = $facet_formatted_args['post_filter'];

return $args;
}

/**
* Output scripts for widget admin
*
Expand Down Expand Up @@ -387,14 +396,57 @@ public function get_selected() {
/**
* Build query url
*
* @since 2.5, deprecated in 4.3.0
* @since 2.5
* @param array $filters Facet filters
* @return string
*/
public function build_query_url( $filters ) {
_deprecated_function( __METHOD__, '4.3.0', "\ElasticPress\Features::factory()->get_registered_feature( 'facets' )->types['taxonomy']->build_query_url()" );
$query_param = array();

foreach ( $this->types as $type_obj ) {
$filter_type = $type_obj->get_filter_type();

if ( ! empty( $filters[ $filter_type ] ) ) {
$type_filters = $filters[ $filter_type ];

foreach ( $type_filters as $facet => $filter ) {
if ( ! empty( $filter['terms'] ) ) {
$query_param[ $type_obj->get_filter_name() . $facet ] = implode( ',', array_keys( $filter['terms'] ) );
}
}
}
}

$feature = Features::factory()->get_registered_feature( 'facets' );
$allowed_args = $feature->get_allowed_query_args();

if ( ! empty( $filters ) ) {
foreach ( $filters as $filter => $value ) {
if ( ! empty( $value ) && in_array( $filter, $allowed_args, true ) ) {
$query_param[ $filter ] = $value;
}
}
}

$query_string = http_build_query( $query_param );

/**
* Filter facet query string
*
* @hook ep_facet_query_string
* @param {string} $query_string Current query string
* @param {array} $query_param Query parameters
* @return {string} New query string
*/
$query_string = apply_filters( 'ep_facet_query_string', $query_string, $query_param );

$url = $_SERVER['REQUEST_URI'];
$pagination = strpos( $url, '/page' );
if ( false !== $pagination ) {
$url = substr( $url, 0, $pagination );
}

return $this->types['taxonomy']->build_query_url( $filters );
return strtok( trailingslashit( $url ), '?' ) . ( ( ! empty( $query_string ) ) ? '?' . $query_string : '' );
}

/**
Expand Down
14 changes: 13 additions & 1 deletion includes/classes/Feature/Facets/Types/Taxonomy/Block.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,19 @@ public function setup() {
add_action( 'init', [ $this, 'register_block' ] );
add_action( 'rest_api_init', [ $this, 'setup_endpoints' ] );

$this->renderer = new Renderer();
/**
* Filter the class name to be used to render the Facet.
*
* @since 4.3.0
* @hook ep_facet_renderer_class
* @param {string} $classname The name of the class to be instantiated and used as a renderer.
* @param {string} $facet_type The type of the facet.
* @param {string} $context Context where the renderer will be used: `block` or `widget`, for example.
* @return {string} The name of the class
*/
$renderer_class = apply_filters( 'ep_facet_renderer_class', __NAMESPACE__ . '\Renderer', 'taxonomy', 'block' );

$this->renderer = new $renderer_class();
}

/**
Expand Down
85 changes: 9 additions & 76 deletions includes/classes/Feature/Facets/Types/Taxonomy/FacetType.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ class FacetType {
*/
public function setup() {
add_action( 'widgets_init', [ $this, 'register_widgets' ] );
add_filter( 'ep_post_formatted_args', [ $this, 'set_agg_filters' ], 10, 3 );
add_filter( 'ep_facet_agg_filters', [ $this, 'agg_filters' ] );
add_action( 'pre_get_posts', [ $this, 'facet_query' ] );
add_filter( 'ep_facet_wp_query_aggs_facet', [ $this, 'set_wp_query_aggs' ] );

Expand All @@ -39,20 +39,13 @@ public function setup() {
/**
* If we are doing or matches, we need to remove filters from aggs
*
* @param array $args ES arguments
* @param array $query_args Query arguments
* @param WP_Query $query WP Query instance
* @param array $query_args Query arguments
* @return array
*/
public function set_agg_filters( $args, $query_args, $query ) {
// Not a facetable query
if ( empty( $query_args['ep_facet'] ) ) {
return $args;
}

public function agg_filters( $query_args ) {
// Without taxonomies there is nothing to do here.
if ( empty( $query_args['tax_query'] ) ) {
return $args;
return $query_args;
}

$feature = Features::factory()->get_registered_feature( 'facets' );
Expand All @@ -63,81 +56,21 @@ public function set_agg_filters( $args, $query_args, $query ) {
)
);

$facet_query_args = $query_args;

if ( 'any' === $settings['match_type'] ) {
foreach ( $facet_query_args['tax_query'] as $key => $taxonomy ) {
foreach ( $query_args['tax_query'] as $key => $taxonomy ) {
if ( is_array( $taxonomy ) ) {
unset( $facet_query_args['tax_query'][ $key ] );
unset( $query_args['tax_query'][ $key ] );
}
}
}

// @todo For some reason these are appearing in the query args, need to investigate
$unwanted_args = [ 'category_name', 'cat', 'tag', 'tag_id', 'taxonomy', 'term' ];
foreach ( $unwanted_args as $unwanted_arg ) {
unset( $facet_query_args[ $unwanted_arg ] );
}

remove_filter( 'ep_post_formatted_args', [ $this, 'set_agg_filters' ], 10, 3 );
$facet_formatted_args = Indexables::factory()->get( 'post' )->format_args( $facet_query_args, $query );
add_filter( 'ep_post_formatted_args', [ $this, 'set_agg_filters' ], 10, 3 );

$args['aggs']['terms']['filter'] = $facet_formatted_args['post_filter'];

return $args;
}


/**
* Build query url
*
* @param array $filters Facet filters
* @return string
*/
public function build_query_url( $filters ) {
$query_param = array();

if ( ! empty( $filters['taxonomies'] ) ) {
$tax_filters = $filters['taxonomies'];

foreach ( $tax_filters as $taxonomy => $filter ) {
if ( ! empty( $filter['terms'] ) ) {
$query_param[ $this->get_filter_name() . $taxonomy ] = implode( ',', array_keys( $filter['terms'] ) );
}
}
}

$feature = Features::factory()->get_registered_feature( 'facets' );
$allowed_args = $feature->get_allowed_query_args();

if ( ! empty( $filters ) ) {
foreach ( $filters as $filter => $value ) {
if ( ! empty( $value ) && in_array( $filter, $allowed_args, true ) ) {
$query_param[ $filter ] = $value;
}
}
unset( $query_args[ $unwanted_arg ] );
}

$query_string = http_build_query( $query_param );

/**
* Filter facet query string
*
* @hook ep_facet_query_string
* @param {string} $query_string Current query string
* @param {array} $query_param Query parameters
* @return {string} New query string
*/
$query_string = apply_filters( 'ep_facet_query_string', $query_string, $query_param );

$url = $_SERVER['REQUEST_URI'];
$pagination = strpos( $url, '/page' );
if ( false !== $pagination ) {
$url = substr( $url, 0, $pagination );
}

return strtok( trailingslashit( $url ), '?' ) . ( ( ! empty( $query_string ) ) ? '?' . $query_string : '' );
return $query_args;
}

/**
Expand Down Expand Up @@ -174,7 +107,7 @@ public function get_filter_type() {
* Filter the facet filter name that's added to the URL
*
* @hook ep_facet_filter_name
* @since 4.0.0
* @since 4.3.0
* @param {string} Facet filter name
* @return {string} New facet filter name
*/
Expand Down
10 changes: 3 additions & 7 deletions includes/classes/Feature/Facets/Types/Taxonomy/Renderer.php
Original file line number Diff line number Diff line change
Expand Up @@ -75,12 +75,8 @@ public function render( $args, $instance ) {
}
}

$facet_type = $feature->types['taxonomy'];

$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
*/
Expand Down Expand Up @@ -196,7 +192,7 @@ public function render( $args, $instance ) {
// phpcs:disable WordPress.Security.EscapeOutput.OutputNotEscaped
echo $this->get_facet_term_html(
$term,
$facet_type->build_query_url( $new_filters ),
$feature->build_query_url( $new_filters ),
true
);
// phpcs:enable WordPress.Security.EscapeOutput.OutputNotEscaped
Expand Down Expand Up @@ -259,7 +255,7 @@ public function render( $args, $instance ) {
// phpcs:disable WordPress.Security.EscapeOutput.OutputNotEscaped
echo $this->get_facet_term_html(
$term,
$facet_type->build_query_url( $new_filters ),
$feature->build_query_url( $new_filters ),
$selected
);
// phpcs:enable WordPress.Security.EscapeOutput.OutputNotEscaped
Expand Down Expand Up @@ -288,7 +284,7 @@ public function render( $args, $instance ) {
// phpcs:disable WordPress.Security.EscapeOutput.OutputNotEscaped
echo $this->get_facet_term_html(
$term,
$facet_type->build_query_url( $new_filters )
$feature->build_query_url( $new_filters )
);
// phpcs:enable WordPress.Security.EscapeOutput.OutputNotEscaped
endforeach;
Expand Down
5 changes: 4 additions & 1 deletion includes/classes/Feature/Facets/Types/Taxonomy/Widget.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,10 @@ public function __construct() {

parent::__construct( 'ep-facet', esc_html__( 'ElasticPress - Facet', 'elasticpress' ), $options );

$this->renderer = new Renderer();
/** This filter is documented in includes/classes/Feature/Facets/Types/Taxonomy/Block.php */
$renderer_class = apply_filters( 'ep_facet_renderer_class', __NAMESPACE__ . '\Renderer', 'taxonomy', 'widget' );

$this->renderer = new $renderer_class();
}

/**
Expand Down