PluginProbe
ElasticPress / 5.3.5
ElasticPress v5.3.5
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 / SyncManager.php

SyncManager.php in ElasticPress 5.3.5, at includes/classes/SyncManager.php

356 lines 8.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * SyncManager common functionality
4 *
5 * @package elasticpress
6 * @since 3.0
7 */
8
9 namespace ElasticPress;
10
11 use ElasticPress\Utils;
12
13 /**
14 * Abstract sync manager class to be extended for each indexable
15 */
16 abstract class SyncManager {
17
18 /**
19 * Save objects for indexing later
20 *
21 * @since 3.0
22 * @var array
23 */
24 public $sync_queue = [];
25
26 /**
27 * Indexable slug
28 *
29 * @var string
30 * @since 3.0
31 */
32 public $indexable_slug;
33
34 /**
35 * Create new SyncManager
36 *
37 * @param string $indexable_slug Indexable slug.
38 * @since 3.0
39 */
40 public function __construct( $indexable_slug ) {
41 $this->indexable_slug = $indexable_slug;
42
43 if ( defined( 'EP_SYNC_CHUNK_LIMIT' ) && is_numeric( EP_SYNC_CHUNK_LIMIT ) ) {
44 /**
45 * We also sync when we exceed Chunk limit set.
46 * This is sometimes useful when posts are generated programmatically.
47 */
48 add_action( 'ep_after_add_to_queue', [ $this, 'index_sync_on_chunk_limit' ] );
49 }
50 /**
51 * We do all syncing on shutdown or redirect
52 */
53 add_action( 'shutdown', [ $this, 'index_sync_queue' ] );
54 add_filter( 'wp_redirect', [ $this, 'index_sync_queue_on_redirect' ], 10, 1 );
55
56 /**
57 * Actions for multisite
58 */
59 add_action( 'delete_blog', array( $this, 'action_delete_blog_from_index' ) );
60 add_action( 'make_delete_blog', array( $this, 'action_delete_blog_from_index' ) );
61 add_action( 'make_spam_blog', array( $this, 'action_delete_blog_from_index' ) );
62 add_action( 'archive_blog', array( $this, 'action_delete_blog_from_index' ) );
63 add_action( 'deactivate_blog', array( $this, 'action_delete_blog_from_index' ) );
64
65 // Implemented by children.
66 $this->setup();
67 }
68
69 /**
70 * Get sync queue.
71 *
72 * @since 5.0.0
73 * @param int $blog_id Blog ID to retrieve queue.
74 * @return array
75 */
76 public function get_sync_queue( $blog_id = false ) {
77 if ( ! $blog_id ) {
78 $blog_id = get_current_blog_id();
79 }
80
81 if ( ! isset( $this->sync_queue[ $blog_id ] ) ) {
82 $this->sync_queue[ $blog_id ] = [];
83 }
84
85 return $this->sync_queue[ $blog_id ];
86 }
87
88 /**
89 * Add an object to the sync queue.
90 *
91 * @since 3.1.2
92 *
93 * @param int $object_id Object ID to sync.
94 * @return boolean
95 */
96 public function add_to_queue( $object_id ) {
97 if ( ! is_numeric( $object_id ) ) {
98 return false;
99 }
100
101 $current_blog_id = get_current_blog_id();
102 if ( ! isset( $this->sync_queue[ $current_blog_id ] ) ) {
103 $this->sync_queue[ $current_blog_id ] = [];
104 }
105
106 $this->sync_queue[ $current_blog_id ][ $object_id ] = true;
107
108 /**
109 * Fires after item is added to sync queue
110 *
111 * @hook ep_after_add_to_queue
112 * @param {int} $object_id ID of object
113 * @param {array} $sync_queue Current sync queue
114 * @since 3.1.2
115 */
116 do_action( 'ep_after_add_to_queue', $object_id, $this->get_sync_queue() );
117
118 return true;
119 }
120
121 /**
122 * Remove an object from the sync queue.
123 *
124 * @since 3.5
125 *
126 * @param int $object_id Object ID to remove from the queue.
127 * @return boolean
128 */
129 public function remove_from_queue( $object_id ) {
130 if ( ! is_numeric( $object_id ) ) {
131 return false;
132 }
133
134 $current_blog_id = get_current_blog_id();
135 if ( ! isset( $this->sync_queue[ $current_blog_id ] ) ) {
136 $this->sync_queue[ $current_blog_id ] = [];
137 }
138
139 unset( $this->sync_queue[ $current_blog_id ][ $object_id ] );
140
141 /**
142 * Fires after item is removed from sync queue
143 *
144 * @hook ep_after_remove_from_queue
145 * @param {int} $object_id ID of object
146 * @param {array} $sync_queue Current sync queue
147 * @since 3.5
148 */
149 do_action( 'ep_after_remove_from_queue', $object_id, $this->get_sync_queue() );
150
151 return true;
152 }
153
154 /**
155 * Reset the sync queue.
156 *
157 * @since 5.0.0
158 * @param int $blog_id Blog ID to reset queue
159 */
160 public function reset_sync_queue( $blog_id = false ) {
161 if ( ! $blog_id ) {
162 $blog_id = get_current_blog_id();
163 }
164
165 $this->sync_queue[ $blog_id ] = [];
166 }
167
168 /**
169 * Sync queued objects if the EP_SYNC_CHUNK_LIMIT is reached.
170 *
171 * @since 3.1.2
172 * @return boolean
173 */
174 public function index_sync_on_chunk_limit() {
175 if ( defined( 'EP_SYNC_CHUNK_LIMIT' ) && is_numeric( EP_SYNC_CHUNK_LIMIT ) &&
176 is_array( $this->get_sync_queue() ) && count( $this->get_sync_queue() ) > EP_SYNC_CHUNK_LIMIT ) {
177 $this->index_sync_queue();
178 }
179 return true;
180 }
181
182 /**
183 * Sync queued objects before a redirect occurs. Hackish but very important since
184 * shutdown won't be firing
185 *
186 * @param string $location Redirect location.
187 * @since 3.0
188 * @return string
189 */
190 public function index_sync_queue_on_redirect( $location ) {
191 $this->index_sync_queue();
192
193 return $location;
194 }
195
196 /**
197 * Sync objects in queue.
198 *
199 * @since 3.0
200 */
201 public function index_sync_queue() {
202 if ( empty( $this->sync_queue ) ) {
203 return;
204 }
205
206 $current_blog_id = get_current_blog_id();
207 foreach ( $this->sync_queue as $blog_id => $sync_queue ) {
208 if ( empty( $sync_queue ) ) {
209 continue;
210 }
211
212 if ( $current_blog_id !== $blog_id ) {
213 switch_to_blog( $blog_id );
214 }
215
216 /**
217 * Allow other code to intercept the sync process
218 *
219 * @hook pre_ep_index_sync_queue
220 * @param {boolean} $bail True to skip the rest of index_sync_queue(), false to continue normally
221 * @param {SyncManager} $sync_manager SyncManager instance for the indexable
222 * @param {string} $indexable_slug Slug of the indexable being synced
223 * @since 3.5
224 */
225 if ( apply_filters( 'pre_ep_index_sync_queue', false, $this, $this->indexable_slug ) ) {
226 return;
227 }
228
229 /**
230 * Backwards compat for pre-3.0
231 */
232 foreach ( $sync_queue as $object_id => $value ) {
233 /**
234 * Fires when object in queue are synced
235 *
236 * @hook ep_sync_on_meta_update_queue
237 * @param {int} $object_id ID of object
238 */
239 do_action( 'ep_sync_on_meta_update', $object_id );
240 }
241
242 // Bulk sync them all.
243 Indexables::factory()->get( $this->indexable_slug )->bulk_index_dynamically( array_keys( $this->get_sync_queue( $blog_id ) ) );
244
245 /**
246 * Make sure to reset sync queue in case an shutdown happens before a redirect
247 * when a redirect has already been triggered.
248 */
249 $this->reset_sync_queue( $blog_id );
250
251 if ( $current_blog_id !== $blog_id ) {
252 restore_current_blog();
253 }
254 }
255 }
256
257 /**
258 * Check if we can index content in the current blog
259 *
260 * @since 3.5
261 * @return boolean
262 */
263 public function can_index_site() {
264 if ( ( defined( 'EP_IS_NETWORK' ) && EP_IS_NETWORK ) && ! Utils\is_site_indexable() ) {
265 $this->tear_down();
266 return false;
267 }
268
269 return true;
270 }
271
272 /**
273 * Determine whether syncing an indexable should take place.
274 *
275 * Returns true or false depending on the value of the WP_IMPORTING global.
276 * Contains the 'ep_sync_indexable_kill' filter that enables overriding the default behavior.
277 *
278 * @since 3.4.2
279 * @return bool
280 */
281 public function kill_sync() {
282
283 $is_importing = defined( 'WP_IMPORTING' ) && true === WP_IMPORTING;
284
285 /**
286 * Filter whether to bypass sync.
287 *
288 * @since 3.4.2
289 * @hook ep_sync_indexable_kill
290 * @param {boolean} $kill True if WP_IMPORTING is defined and true, else false.
291 * @param {array} $indexable_slug Indexable slug.
292 */
293 return apply_filters( 'ep_sync_indexable_kill', $is_importing, $this->indexable_slug );
294 }
295
296 /**
297 * Remove blog from index when a site is deleted, archived, or deactivated
298 *
299 * @param int $blog_id WP Blog ID.
300 */
301 public function action_delete_blog_from_index( $blog_id ) {
302 if ( $this->kill_sync() ) {
303 return;
304 }
305
306 $indexable = Indexables::factory()->get( $this->indexable_slug );
307
308 // Don't delete global indexes
309 if ( $indexable->global ) {
310 return;
311 }
312
313 /**
314 * Filter to whether to keep index on site deletion
315 *
316 * @hook ep_keep_index
317 * @since 3.0
318 * @since 3.6.2 Moved from Post\SyncManager to the main SyncManager class
319 * @since 3.6.5 Added `$blog_id` and `$indexable_slug`
320 * @param {bool} $keep True means don't delete index
321 * @param {int} $blog_id WP Blog ID
322 * @param {string} $indexable_slug Indexable slug
323 * @return {bool} New value
324 */
325 if ( $indexable->index_exists( $blog_id ) && ! apply_filters( 'ep_keep_index', false, $blog_id, $this->indexable_slug ) ) {
326 $indexable->delete_index( $blog_id );
327 }
328 }
329
330 /**
331 * Clear the cache of the total fields limit
332 *
333 * @since 4.7.0
334 */
335 public function clear_index_settings_cache() {
336 $indexable = Indexables::factory()->get( $this->indexable_slug );
337 $cache_key = 'ep_index_settings_' . $indexable->get_index_name();
338
339 Utils\delete_transient( $cache_key );
340 }
341
342 /**
343 * Implementation should setup hooks/filters
344 *
345 * @since 3.0
346 */
347 abstract public function setup();
348
349 /**
350 * Implementation (for multisite) should un-setup hooks/filters if applicable.
351 *
352 * @since 4.0
353 */
354 abstract public function tear_down();
355 }
356