PluginProbe
ElasticPress / 4.2.0
ElasticPress v4.2.0
5.3.5 5.3.4 3.6.5 3.6.6 4.0.0 4.0.1 4.1.0 4.2.0 4.2.1 4.2.2 4.3.0 4.3.1 4.4.0 4.4.1 4.5.0 4.5.1 4.5.2 4.6.0 4.6.1 4.7.0 4.7.1 4.7.2 5.0.0 5.0.1 5.0.2 All 108 releases
elasticpress / includes / classes / Indexable / Term / QueryIntegration.php

QueryIntegration.php in ElasticPress 4.2.0, at includes/classes/Indexable/Term/QueryIntegration.php

335 lines 9.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Integrate with WP_Term_Query
4 *
5 * @since 3.1
6 * @package elasticpress
7 */
8
9 namespace ElasticPress\Indexable\Term;
10
11 use ElasticPress\Indexables as Indexables;
12 use \WP_Term_Query as WP_Term_Query;
13 use ElasticPress\Utils as Utils;
14
15 if ( ! defined( 'ABSPATH' ) ) {
16 exit; // Exit if accessed directly.
17 }
18
19 /**
20 * Query integration class
21 */
22 class QueryIntegration {
23
24 /**
25 * Checks to see if we should be integrating and if so, sets up the appropriate actions and filters.
26 *
27 * @param string $indexable_slug Indexable slug. Optional.
28 *
29 * @since 3.1
30 * @since 3.6.0 Added $indexable_slug
31 */
32 public function __construct( $indexable_slug = 'term' ) {
33 // Ensure that we are currently allowing ElasticPress to override the normal WP_Query
34 // Indexable->is_full_reindexing() is not available at this point yet, so using the IndexHelper version of it.
35 if ( \ElasticPress\IndexHelper::factory()->is_full_reindexing( $indexable_slug, get_current_blog_id() ) ) {
36 return;
37 }
38
39 // Add header
40 add_action( 'pre_get_terms', array( $this, 'action_pre_get_terms' ), 5 );
41
42 // Filter term query
43 add_filter( 'terms_pre_query', [ $this, 'maybe_filter_query' ], 10, 2 );
44 }
45
46 /**
47 * Add EP header
48 *
49 * @param WP_Term_Query $query Query object
50 * @since 3.1
51 * @return void
52 */
53 public function action_pre_get_terms( WP_Term_Query $query ) {
54 if ( ! Indexables::factory()->get( 'term' )->elasticpress_enabled( $query ) || apply_filters( 'ep_skip_term_query_integration', false, $query ) ) {
55 return;
56 }
57
58 if ( ! headers_sent() ) {
59 /**
60 * Manually setting a header as $wp_query isn't yet initialized
61 * when we call: add_filter('wp_headers', 'filter_wp_headers');
62 */
63 header( 'X-ElasticPress-Term-Search: true' );
64 }
65 }
66
67 /**
68 * If WP_Term_Query meets certain conditions, query results from ES
69 *
70 * @param array $results Term results.
71 * @param WP_Term_Query $query Current query.
72 * @since 3.1
73 * @return array
74 */
75 public function maybe_filter_query( $results, WP_Term_Query $query ) {
76 $indexable = Indexables::factory()->get( 'term' );
77
78 if ( ! $indexable->elasticpress_enabled( $query ) || apply_filters( 'ep_skip_term_query_integration', false, $query ) ) {
79 return $results;
80 }
81
82 $new_terms = apply_filters( 'ep_wp_query_cached_terms', null, $query );
83
84 if ( null === $new_terms ) {
85 $formatted_args = $indexable->format_args( $query->query_vars );
86
87 $scope = 'current';
88 if ( ! empty( $query->query_vars['sites'] ) ) {
89 $scope = $query->query_vars['sites'];
90 }
91
92 /**
93 * Filter search scope
94 *
95 * @since 3.1
96 *
97 * @param mixed $scope The search scope. Accepts `all` (string), a single
98 * site id (int or string), or an array of site ids (array).
99 */
100 $scope = apply_filters( 'ep_term_search_scope', $scope );
101
102 if ( ! defined( 'EP_IS_NETWORK' ) || ! EP_IS_NETWORK ) {
103 $scope = 'current';
104 }
105
106 $index = null;
107
108 if ( 'all' === $scope ) {
109 $index = $indexable->get_network_alias();
110 } elseif ( is_numeric( $scope ) ) {
111 $index = $indexable->get_index_name( (int) $scope );
112 } elseif ( is_array( $scope ) ) {
113 $index = [];
114
115 foreach ( $scope as $site_id ) {
116 $index[] = $indexable->get_index_name( $site_id );
117 }
118
119 $index = implode( ',', $index );
120 }
121
122 $ep_query = $indexable->query_es( $formatted_args, $query->query_vars, $index );
123
124 if ( false === $ep_query ) {
125 $query->elasticsearch_success = false;
126 return $results;
127 }
128
129 /**
130 * Elasticsearch 5 will return found_documents as a number,
131 * ES 7+ will return it as an object with `value`. If any of that is found,
132 * fallback to a simple count of returned documents.
133 *
134 * @since 3.6.3
135 */
136 if ( is_integer( $ep_query['found_documents'] ) ) {
137 $query->found_terms = $ep_query['found_documents'];
138 } elseif ( is_array( $ep_query['found_documents'] ) && isset( $ep_query['found_documents']['value'] ) ) {
139 $query->found_terms = $ep_query['found_documents']['value'];
140 } else {
141 $query->found_terms = count( $ep_query['documents'] );
142 }
143
144 $query->elasticsearch_success = true;
145
146 // Determine how we should format the results from ES based on the fields parameter.
147 $fields = $query->query_vars['fields'];
148
149 $new_terms = [];
150
151 switch ( $fields ) {
152 case 'all_with_object_id':
153 $new_terms = $this->format_hits_as_terms( $ep_query['documents'], $new_terms, $query->query_vars );
154 break;
155
156 case 'count':
157 $new_terms = count( $ep_query['documents'] );
158 break;
159
160 case 'ids':
161 $new_terms = $this->format_hits_as_ids( $ep_query['documents'], $new_terms );
162 break;
163
164 case 'id=>name':
165 $new_terms = $this->format_hits_as_id_name( $ep_query['documents'], $new_terms );
166 break;
167
168 case 'id=>parent':
169 $new_terms = $this->format_hits_as_id_parent( $ep_query['documents'], $new_terms );
170 break;
171
172 case 'id=>slug':
173 $new_terms = $this->format_hits_as_id_slug( $ep_query['documents'], $new_terms );
174 break;
175
176 case 'names':
177 $new_terms = $this->format_hits_as_names( $ep_query['documents'], $new_terms );
178 break;
179
180 case 'tt_ids':
181 $new_terms = $this->format_hits_as_ids( $ep_query['documents'], $new_terms, 'term_taxonomy_id' );
182 break;
183
184 default:
185 $new_terms = $this->format_hits_as_terms( $ep_query['documents'], $new_terms, $query->query_vars );
186 break;
187 }
188
189 if ( ! empty( $query->query_vars['count'] ) ) {
190 $new_terms = count( $ep_query['documents'] );
191 }
192 }
193
194 return $new_terms;
195 }
196
197 /**
198 * Format the ES hits/results as term objects.
199 *
200 * @param array $terms The terms that should be formatted.
201 * @param array $new_terms Array of terms from cache.
202 * @param array $query_vars Query variables.
203 * @since 3.1
204 * @return array
205 */
206 protected function format_hits_as_terms( $terms, $new_terms, $query_vars ) {
207 foreach ( $terms as $term_array ) {
208 $term = new \stdClass();
209
210 $term->ID = $term_array['term_id'];
211 $term->site_id = get_current_blog_id();
212
213 if ( ! empty( $term_array['site_id'] ) ) {
214 $term->site_id = $term_array['site_id'];
215 }
216
217 $term_return_args = apply_filters(
218 'ep_search_term_return_args',
219 array(
220 'term_id',
221 'name',
222 'slug',
223 'term_group',
224 'term_taxonomy_id',
225 'taxonomy',
226 'description',
227 'parent',
228 'count',
229 'meta',
230 )
231 );
232
233 foreach ( $term_return_args as $key ) {
234 if ( isset( $term_array[ $key ] ) ) {
235 if ( 'count' === $key && ! empty( $query_vars['pad_counts'] ) ) {
236 $term_array[ $key ] += $term_array['hierarchy']['children']['count'];
237 }
238
239 $term->$key = $term_array[ $key ];
240 }
241 }
242
243 $term->elasticsearch = true; // Super useful for debugging.
244
245 if ( $term ) {
246 $new_terms[] = $term;
247 }
248 }
249
250 return $new_terms;
251 }
252
253 /**
254 * Format the ES hits/results as an array of ids.
255 *
256 * @param array $terms The terms that should be formatted.
257 * @param array $new_terms Array of terms from cache.
258 * @param string $type Type of ID to return. Default 'term_id'.
259 * @since 3.1
260 * @return array
261 */
262 protected function format_hits_as_ids( $terms, $new_terms, $type = 'term_id' ) {
263 foreach ( $terms as $term_array ) {
264 $new_terms[] = 'term_id' === $type ? $term_array['term_id'] : $term_array['term_taxonomy_id'];
265 }
266
267 return $new_terms;
268 }
269
270 /**
271 * Format the ES hits/results as an array of term ID and term name.
272 *
273 * @param array $terms The terms that should be formatted.
274 * @param array $new_terms Array of terms from cache.
275 * @since 3.1
276 * @return array Returns an associative array with ids as keys, term names as values
277 */
278 protected function format_hits_as_id_name( $terms, $new_terms ) {
279 foreach ( $terms as $term_array ) {
280 $new_terms[ $term_array['term_id'] ] = $term_array['name'];
281 }
282
283 return $new_terms;
284 }
285
286 /**
287 * Format the ES hits/results as an array of term ID and parent ID.
288 *
289 * @param array $terms The terms that should be formatted.
290 * @param array $new_terms Array of terms from cache.
291 * @since 3.1
292 * @return array Returns an associative array with ids as keys, parent term IDs as values
293 */
294 protected function format_hits_as_id_parent( $terms, $new_terms ) {
295 foreach ( $terms as $term_array ) {
296 $new_terms[ $term_array['term_id'] ] = $term_array['parent'];
297 }
298
299 return $new_terms;
300 }
301
302 /**
303 * Format the ES hits/results as an array of term ID and term slug.
304 *
305 * @param array $terms The terms that should be formatted.
306 * @param array $new_terms Array of terms from cache.
307 * @since 3.1
308 * @return array Returns an associative array with ids as keys, term slugs as values
309 */
310 protected function format_hits_as_id_slug( $terms, $new_terms ) {
311 foreach ( $terms as $term_array ) {
312 $new_terms[ $term_array['term_id'] ] = $term_array['slug'];
313 }
314
315 return $new_terms;
316 }
317
318 /**
319 * Format the ES hits/results as an array of term names.
320 *
321 * @param array $terms The terms that should be formatted.
322 * @param array $new_terms Array of terms from cache.
323 * @since 3.1
324 * @return array Returns an array of term names.
325 */
326 protected function format_hits_as_names( $terms, $new_terms ) {
327 foreach ( $terms as $term_array ) {
328 $new_terms[] = $term_array['name'];
329 }
330
331 return $new_terms;
332 }
333
334 }
335