-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #50 from 10up/feature/ep-issue-3180
Bring the Users feature to ElasticPress Labs
- Loading branch information
Showing
15 changed files
with
3,860 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
<?php | ||
/** | ||
* Users feature | ||
* | ||
* @since 2.1.0 | ||
* @package ElasticPressLabs | ||
*/ | ||
|
||
namespace ElasticPressLabs\Feature; | ||
|
||
use ElasticPress\Feature; | ||
use ElasticPress\Indexables; | ||
use ElasticPress\FeatureRequirementsStatus; | ||
|
||
/** | ||
* Users feature class | ||
*/ | ||
class Users extends Feature { | ||
/** | ||
* Initialize feature setting it's config | ||
*/ | ||
public function __construct() { | ||
$this->slug = 'users'; | ||
|
||
$this->title = esc_html__( 'Users', 'elasticpress' ); | ||
|
||
$this->summary = __( 'Improve user search relevancy and query performance.', 'elasticpress' ); | ||
|
||
$this->docs_url = __( 'https://elasticpress.zendesk.com/hc/en-us/articles/360050447492-Configuring-ElasticPress-via-the-Plugin-Dashboard#users', 'elasticpress' ); | ||
|
||
$this->requires_install_reindex = true; | ||
|
||
Indexables::factory()->register( new \ElasticPressLabs\Indexable\User\User(), false ); | ||
|
||
parent::__construct(); | ||
} | ||
|
||
/** | ||
* Hook search functionality | ||
*/ | ||
public function setup() { | ||
Indexables::factory()->activate( 'user' ); | ||
|
||
add_action( 'init', [ $this, 'search_setup' ] ); | ||
} | ||
|
||
/** | ||
* Setup feature on each page load | ||
*/ | ||
public function search_setup() { | ||
add_filter( 'ep_elasticpress_enabled', [ $this, 'integrate_search_queries' ], 10, 2 ); | ||
} | ||
|
||
/** | ||
* Output feature box long text | ||
*/ | ||
public function output_feature_box_long() { | ||
?> | ||
<p><?php esc_html_e( 'This feature will empower your website to overcome traditional WordPress user search and query limitations that can present themselves at scale.', 'elasticpress' ); ?></p> | ||
<p><?php esc_html_e( 'Be aware that storing user data may bound you to certain legal obligations depending on your local government regulations.', 'elasticpress' ); ?></p> | ||
<?php | ||
} | ||
|
||
/** | ||
* Enable integration on search queries | ||
* | ||
* @param bool $enabled Whether EP is enabled | ||
* @param WP_User_Query $query Current query object. | ||
* @return bool | ||
*/ | ||
public function integrate_search_queries( $enabled, $query ) { | ||
if ( ! is_a( $query, 'WP_User_Query' ) ) { | ||
return $enabled; | ||
} | ||
|
||
if ( isset( $query->query_vars['ep_integrate'] ) && ! filter_var( $query->query_vars['ep_integrate'], FILTER_VALIDATE_BOOLEAN ) ) { | ||
$enabled = false; | ||
} elseif ( ! empty( $query->query_vars['search'] ) ) { | ||
$enabled = true; | ||
} | ||
|
||
return $enabled; | ||
} | ||
|
||
/** | ||
* Determine feature reqs status | ||
* | ||
* @return FeatureRequirementsStatus | ||
*/ | ||
public function requirements_status() { | ||
$status = new FeatureRequirementsStatus( 1 ); | ||
|
||
return $status; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,207 @@ | ||
<?php | ||
/** | ||
* Integrate with WP_User_Query | ||
* | ||
* @since 2.1.0 | ||
* @package ElasticPressLabs | ||
*/ | ||
|
||
namespace ElasticPressLabs\Indexable\User; | ||
|
||
use ElasticPress\Indexables; | ||
use \WP_User_Query; | ||
|
||
if ( ! defined( 'ABSPATH' ) ) { | ||
exit; // Exit if accessed directly. | ||
} | ||
|
||
/** | ||
* Query integration class | ||
*/ | ||
class QueryIntegration { | ||
|
||
/** | ||
* Checks to see if we should be integrating and if so, sets up the appropriate actions and filters. | ||
* | ||
* @param string $indexable_slug Indexable slug. Optional. | ||
*/ | ||
public function __construct( $indexable_slug = 'user' ) { | ||
// Ensure that we are currently allowing ElasticPress to override the normal WP_Query | ||
// Indexable->is_full_reindexing() is not available at this point yet, so using the IndexHelper version of it. | ||
if ( \ElasticPress\IndexHelper::factory()->is_full_reindexing( $indexable_slug ) ) { | ||
return; | ||
} | ||
|
||
add_filter( 'users_pre_query', [ $this, 'maybe_filter_query' ], 10, 2 ); | ||
|
||
// Add header | ||
add_action( 'pre_get_users', array( $this, 'action_pre_get_users' ), 5 ); | ||
} | ||
|
||
/** | ||
* If WP_User_Query meets certain conditions, query results from ES | ||
* | ||
* @param array $results Users array. | ||
* @param WP_User_Query $query Current query. | ||
* @return array | ||
*/ | ||
public function maybe_filter_query( $results, WP_User_Query $query ) { | ||
$user_indexable = Indexables::factory()->get( 'user' ); | ||
|
||
/** | ||
* Filter to skip user query integration | ||
* | ||
* @hook ep_skip_user_query_integration | ||
* @param {bool} $skip True meanas skip query | ||
* @param {WP_User_Query} $query User query | ||
* @since 2.1.0 | ||
* @return {boolean} New value | ||
*/ | ||
if ( ! $user_indexable->elasticpress_enabled( $query ) || apply_filters( 'ep_skip_user_query_integration', false, $query ) ) { | ||
return $results; | ||
} | ||
|
||
/** | ||
* Filter cached user query users | ||
* | ||
* @hook ep_wp_query_search_cached_users | ||
* @param {array} $users Array of users | ||
* @param {WP_User_Query} $query User query | ||
* @since 2.1.0 | ||
* @return {array} New users | ||
*/ | ||
$new_users = apply_filters( 'ep_wp_query_search_cached_users', null, $query ); | ||
|
||
if ( null === $new_users ) { | ||
$formatted_args = $user_indexable->format_args( $query->query_vars, $query ); | ||
|
||
$ep_query = $user_indexable->query_es( $formatted_args, $query->query_vars, null, $query ); | ||
|
||
if ( false === $ep_query ) { | ||
return $results; | ||
} | ||
|
||
/** | ||
* WP_User_Query does not let us set this property: | ||
* | ||
* $query->elasticsearch_success = true; | ||
*/ | ||
$query->query_vars['elasticsearch_success'] = true; | ||
|
||
$fields = $query->get( 'fields' ); | ||
$new_users = []; | ||
|
||
if ( in_array( $fields, [ 'all', 'all_with_meta' ], true ) ) { | ||
foreach ( $ep_query['documents'] as $document ) { | ||
$new_users[] = $document['ID']; | ||
} | ||
} elseif ( is_array( $fields ) ) { | ||
// WP_User_Query returns a stdClass. | ||
foreach ( $ep_query['documents'] as $document ) { | ||
|
||
$user = new \stdClass(); | ||
$user->elasticsearch = true; // Super useful for debugging. | ||
|
||
foreach ( $fields as $field ) { | ||
if ( 'id' === $field ) { | ||
$field = 'ID'; | ||
} | ||
$user->$field = $document[ $field ]; | ||
} | ||
|
||
$new_users[] = $user; | ||
} | ||
} elseif ( is_string( $fields ) && ! empty( $fields ) ) { | ||
foreach ( $ep_query['documents'] as $document ) { | ||
$new_users[] = $document[ $fields ]; | ||
} | ||
} else { | ||
$new_users = $this->format_hits_as_users( $ep_query['documents'] ); | ||
} | ||
} | ||
|
||
$query->total_users = is_array( $ep_query['found_documents'] ) ? $ep_query['found_documents']['value'] : $ep_query['found_documents']; // 7.0+ have this as an array rather than int; | ||
|
||
return $new_users; | ||
} | ||
|
||
/** | ||
* Format the ES hits/results as WP_User objects. | ||
* | ||
* @param array $users The users that should be formatted. | ||
* @return array | ||
*/ | ||
protected function format_hits_as_users( $users ) { | ||
$new_users = []; | ||
|
||
foreach ( $users as $user_array ) { | ||
$user = new \stdClass(); | ||
|
||
/** | ||
* Filter arguments inserted into user object after search | ||
* | ||
* @hook ep_search_user_return_args | ||
* @param {array} $args Array of arguments | ||
* @since 2.1.0 | ||
* @return {array} New arguments | ||
*/ | ||
$user_return_args = apply_filters( | ||
'ep_search_user_return_args', | ||
[ | ||
'ID', | ||
'user_login', | ||
'user_nicename', | ||
'user_email', | ||
'user_url', | ||
'user_registered', | ||
'user_status', | ||
'display_name', | ||
'spam', | ||
'deleted', | ||
'terms', | ||
'meta', | ||
] | ||
); | ||
|
||
foreach ( $user_return_args as $key ) { | ||
if ( isset( $user_array[ $key ] ) ) { | ||
$user->$key = $user_array[ $key ]; | ||
} | ||
} | ||
|
||
$user->elasticsearch = true; // Super useful for debugging. | ||
|
||
$new_users[] = $user; | ||
} | ||
|
||
return $new_users; | ||
} | ||
|
||
/** | ||
* Disables cache_results, adds header. | ||
* | ||
* @param WP_User_Query $query User query | ||
*/ | ||
public function action_pre_get_users( $query ) { | ||
/** | ||
* Filter to skip user query integration | ||
* | ||
* @hook ep_skip_user_query_integration | ||
* @param {bool} $skip True meanas skip query | ||
* @param {WP_User_Query} $query User query | ||
* @since 2.1.0 | ||
* @return {boolean} New value | ||
*/ | ||
if ( ! Indexables::factory()->get( 'user' )->elasticpress_enabled( $query ) || apply_filters( 'ep_skip_user_query_integration', false, $query ) ) { | ||
return; | ||
} | ||
|
||
if ( ! headers_sent() ) { | ||
/** | ||
* Manually setting a header as $wp_query isn't yet initialized | ||
* when we call: add_filter('wp_headers', 'filter_wp_headers'); | ||
*/ | ||
header( 'X-ElasticPress-Search: true' ); | ||
} | ||
} | ||
} |
Oops, something went wrong.