1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* Abstract WP_Background_Process class. |
4
|
|
|
* |
5
|
|
|
* Uses https://github.com/A5hleyRich/wp-background-processing to handle DB |
6
|
|
|
* updates in the background. |
7
|
|
|
* |
8
|
|
|
* @package GeoDirectory |
9
|
|
|
*/ |
10
|
|
|
|
11
|
|
|
defined( 'ABSPATH' ) || exit; |
12
|
|
|
|
13
|
|
|
if ( ! class_exists( 'WP_Async_Request', false ) ) { |
14
|
|
|
include_once( 'libraries/wp-async-request.php' ); |
15
|
|
|
} |
16
|
|
|
|
17
|
|
|
if ( ! class_exists( 'WP_Background_Process', false ) ) { |
18
|
|
|
include_once( 'libraries/wp-background-process.php' ); |
19
|
|
|
} |
20
|
|
|
|
21
|
|
|
/** |
22
|
|
|
* GeoDir_Background_Process class. |
23
|
|
|
*/ |
24
|
|
|
abstract class GeoDir_Background_Process extends WP_Background_Process { |
25
|
|
|
|
26
|
|
|
/** |
27
|
|
|
* Is queue empty. |
28
|
|
|
* |
29
|
|
|
* @return bool |
30
|
|
|
*/ |
31
|
|
View Code Duplication |
protected function is_queue_empty() { |
|
|
|
|
32
|
|
|
global $wpdb; |
33
|
|
|
|
34
|
|
|
$table = $wpdb->options; |
35
|
|
|
$column = 'option_name'; |
36
|
|
|
|
37
|
|
|
if ( is_multisite() ) { |
38
|
|
|
$table = $wpdb->sitemeta; |
39
|
|
|
$column = 'meta_key'; |
40
|
|
|
} |
41
|
|
|
|
42
|
|
|
$key = $wpdb->esc_like( $this->identifier . '_batch_' ) . '%'; |
43
|
|
|
|
44
|
|
|
$count = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM {$table} WHERE {$column} LIKE %s", $key ) ); // @codingStandardsIgnoreLine. |
45
|
|
|
|
46
|
|
|
return ! ( $count > 0 ); |
47
|
|
|
} |
48
|
|
|
|
49
|
|
|
/** |
50
|
|
|
* Get batch. |
51
|
|
|
* |
52
|
|
|
* @return stdClass Return the first batch from the queue. |
53
|
|
|
*/ |
54
|
|
View Code Duplication |
protected function get_batch() { |
|
|
|
|
55
|
|
|
global $wpdb; |
56
|
|
|
|
57
|
|
|
$table = $wpdb->options; |
58
|
|
|
$column = 'option_name'; |
59
|
|
|
$key_column = 'option_id'; |
60
|
|
|
$value_column = 'option_value'; |
61
|
|
|
|
62
|
|
|
if ( is_multisite() ) { |
63
|
|
|
$table = $wpdb->sitemeta; |
64
|
|
|
$column = 'meta_key'; |
65
|
|
|
$key_column = 'meta_id'; |
66
|
|
|
$value_column = 'meta_value'; |
67
|
|
|
} |
68
|
|
|
|
69
|
|
|
$key = $wpdb->esc_like( $this->identifier . '_batch_' ) . '%'; |
70
|
|
|
|
71
|
|
|
$query = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$table} WHERE {$column} LIKE %s ORDER BY {$key_column} ASC LIMIT 1", $key ) ); // @codingStandardsIgnoreLine. |
72
|
|
|
|
73
|
|
|
$batch = new stdClass(); |
74
|
|
|
$batch->key = $query->$column; |
75
|
|
|
$batch->data = array_filter( (array) maybe_unserialize( $query->$value_column ) ); |
76
|
|
|
|
77
|
|
|
return $batch; |
78
|
|
|
} |
79
|
|
|
|
80
|
|
|
/** |
81
|
|
|
* See if the batch limit has been exceeded. |
82
|
|
|
* |
83
|
|
|
* @return bool |
84
|
|
|
*/ |
85
|
|
|
protected function batch_limit_exceeded() { |
86
|
|
|
return $this->time_exceeded() || $this->memory_exceeded(); |
87
|
|
|
} |
88
|
|
|
|
89
|
|
|
/** |
90
|
|
|
* Handle. |
91
|
|
|
* |
92
|
|
|
* Pass each queue item to the task handler, while remaining |
93
|
|
|
* within server memory and time limit constraints. |
94
|
|
|
*/ |
95
|
|
|
protected function handle() { |
96
|
|
|
$this->lock_process(); |
97
|
|
|
|
98
|
|
|
do { |
99
|
|
|
$batch = $this->get_batch(); |
100
|
|
|
|
101
|
|
View Code Duplication |
foreach ( $batch->data as $key => $value ) { |
102
|
|
|
$task = $this->task( $value ); |
103
|
|
|
|
104
|
|
|
if ( false !== $task ) { |
105
|
|
|
$batch->data[ $key ] = $task; |
106
|
|
|
} else { |
107
|
|
|
unset( $batch->data[ $key ] ); |
108
|
|
|
} |
109
|
|
|
|
110
|
|
|
if ( $this->batch_limit_exceeded() ) { |
111
|
|
|
// Batch limits reached. |
112
|
|
|
break; |
113
|
|
|
} |
114
|
|
|
} |
115
|
|
|
|
116
|
|
|
// Update or delete current batch. |
117
|
|
View Code Duplication |
if ( ! empty( $batch->data ) ) { |
118
|
|
|
$this->update( $batch->key, $batch->data ); |
119
|
|
|
} else { |
120
|
|
|
$this->delete( $batch->key ); |
121
|
|
|
} |
122
|
|
|
} while ( ! $this->batch_limit_exceeded() && ! $this->is_queue_empty() ); |
123
|
|
|
|
124
|
|
|
$this->unlock_process(); |
125
|
|
|
|
126
|
|
|
// Start next batch or complete process. |
127
|
|
|
if ( ! $this->is_queue_empty() ) { |
128
|
|
|
$this->dispatch(); |
129
|
|
|
} else { |
130
|
|
|
$this->complete(); |
131
|
|
|
} |
132
|
|
|
} |
133
|
|
|
|
134
|
|
|
/** |
135
|
|
|
* Get memory limit. |
136
|
|
|
* |
137
|
|
|
* @return int |
138
|
|
|
*/ |
139
|
|
View Code Duplication |
protected function get_memory_limit() { |
|
|
|
|
140
|
|
|
if ( function_exists( 'ini_get' ) ) { |
141
|
|
|
$memory_limit = ini_get( 'memory_limit' ); |
142
|
|
|
} else { |
143
|
|
|
// Sensible default. |
144
|
|
|
$memory_limit = '128M'; |
145
|
|
|
} |
146
|
|
|
|
147
|
|
|
if ( ! $memory_limit || -1 === intval( $memory_limit ) ) { |
148
|
|
|
// Unlimited, set to 32GB. |
149
|
|
|
$memory_limit = '32000M'; |
150
|
|
|
} |
151
|
|
|
|
152
|
|
|
return intval( $memory_limit ) * 1024 * 1024; |
153
|
|
|
} |
154
|
|
|
|
155
|
|
|
/** |
156
|
|
|
* Schedule cron healthcheck. |
157
|
|
|
* |
158
|
|
|
* @param array $schedules Schedules. |
159
|
|
|
* @return array |
160
|
|
|
*/ |
161
|
|
View Code Duplication |
public function schedule_cron_healthcheck( $schedules ) { |
|
|
|
|
162
|
|
|
$interval = apply_filters( $this->identifier . '_cron_interval', 5 ); |
163
|
|
|
|
164
|
|
|
if ( property_exists( $this, 'cron_interval' ) ) { |
165
|
|
|
$interval = apply_filters( $this->identifier . '_cron_interval', $this->cron_interval ); |
166
|
|
|
} |
167
|
|
|
|
168
|
|
|
// Adds every 5 minutes to the existing schedules. |
169
|
|
|
$schedules[ $this->identifier . '_cron_interval' ] = array( |
170
|
|
|
'interval' => MINUTE_IN_SECONDS * $interval, |
171
|
|
|
/* translators: %d: interval */ |
172
|
|
|
'display' => sprintf( __( 'Every %d minutes', 'geodirectory' ), $interval ), |
173
|
|
|
); |
174
|
|
|
|
175
|
|
|
return $schedules; |
176
|
|
|
} |
177
|
|
|
|
178
|
|
|
/** |
179
|
|
|
* Delete all batches. |
180
|
|
|
* |
181
|
|
|
* @return GeoDir_Background_Process |
182
|
|
|
*/ |
183
|
|
View Code Duplication |
public function delete_all_batches() { |
|
|
|
|
184
|
|
|
global $wpdb; |
185
|
|
|
|
186
|
|
|
$table = $wpdb->options; |
187
|
|
|
$column = 'option_name'; |
188
|
|
|
|
189
|
|
|
if ( is_multisite() ) { |
190
|
|
|
$table = $wpdb->sitemeta; |
191
|
|
|
$column = 'meta_key'; |
192
|
|
|
} |
193
|
|
|
|
194
|
|
|
$key = $wpdb->esc_like( $this->identifier . '_batch_' ) . '%'; |
195
|
|
|
|
196
|
|
|
$wpdb->query( $wpdb->prepare( "DELETE FROM {$table} WHERE {$column} LIKE %s", $key ) ); // @codingStandardsIgnoreLine. |
197
|
|
|
|
198
|
|
|
return $this; |
199
|
|
|
} |
200
|
|
|
|
201
|
|
|
/** |
202
|
|
|
* Kill process. |
203
|
|
|
* |
204
|
|
|
* Stop processing queue items, clear cronjob and delete all batches. |
205
|
|
|
*/ |
206
|
|
|
public function kill_process() { |
207
|
|
|
if ( ! $this->is_queue_empty() ) { |
208
|
|
|
$this->delete_all_batches(); |
209
|
|
|
wp_clear_scheduled_hook( $this->cron_hook_identifier ); |
210
|
|
|
} |
211
|
|
|
} |
212
|
|
|
} |
213
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.