Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
69.37% |
77 / 111 |
|
50.00% |
4 / 8 |
CRAP | |
0.00% |
0 / 1 |
BulkEdit | |
69.37% |
77 / 111 |
|
50.00% |
4 / 8 |
73.25 | |
0.00% |
0 / 1 |
init | |
100.00% |
10 / 10 |
|
100.00% |
1 / 1 |
3 | |||
bulkEditCustomBox | |
100.00% |
14 / 14 |
|
100.00% |
1 / 1 |
3 | |||
saveBulkEdit | |
92.86% |
13 / 14 |
|
0.00% |
0 / 1 |
9.03 | |||
generateAudioForPosts | |
100.00% |
8 / 8 |
|
100.00% |
1 / 1 |
4 | |||
deleteAudioForPosts | |
0.00% |
0 / 13 |
|
0.00% |
0 / 1 |
30 | |||
bulkActionsEdit | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
1 | |||
handleBulkGenerateAction | |
96.67% |
29 / 30 |
|
0.00% |
0 / 1 |
8 | |||
handleBulkDeleteAction | |
0.00% |
0 / 19 |
|
0.00% |
0 / 1 |
12 |
1 | <?php |
2 | |
3 | declare(strict_types=1); |
4 | |
5 | /** |
6 | * BeyondWords Bulk Edit. |
7 | * |
8 | * Text Domain: beyondwords |
9 | * |
10 | * @package Beyondwords\Wordpress |
11 | * @author Stuart McAlpine <stu@beyondwords.io> |
12 | * @since 3.0.0 |
13 | */ |
14 | |
15 | namespace Beyondwords\Wordpress\Component\Posts\BulkEdit; |
16 | |
17 | use Beyondwords\Wordpress\Core\Core; |
18 | use Beyondwords\Wordpress\Core\CoreUtils; |
19 | use Beyondwords\Wordpress\Component\Settings\SettingsUtils; |
20 | use Beyondwords\Wordpress\Plugin; |
21 | |
22 | /** |
23 | * BulkEdit |
24 | * |
25 | * @since 3.0.0 |
26 | */ |
27 | class BulkEdit |
28 | { |
29 | /** |
30 | * Init. |
31 | * |
32 | * @since 4.0.0 |
33 | */ |
34 | public function init() |
35 | { |
36 | add_action('bulk_edit_custom_box', array($this, 'bulkEditCustomBox'), 10, 2); |
37 | add_action('wp_ajax_save_bulk_edit_beyondwords', array($this, 'saveBulkEdit')); |
38 | |
39 | add_action('wp_loaded', function () { |
40 | $postTypes = SettingsUtils::getCompatiblePostTypes(); |
41 | |
42 | if (is_array($postTypes)) { |
43 | foreach ($postTypes as $postType) { |
44 | add_filter("bulk_actions-edit-{$postType}", array($this, 'bulkActionsEdit'), 10, 1); |
45 | add_filter("handle_bulk_actions-edit-{$postType}", array($this, 'handleBulkDeleteAction'), 10, 3); |
46 | add_filter("handle_bulk_actions-edit-{$postType}", array($this, 'handleBulkGenerateAction'), 10, 3); |
47 | } |
48 | } |
49 | }); |
50 | } |
51 | |
52 | /** |
53 | * Adds the meta box container. |
54 | */ |
55 | public function bulkEditCustomBox($columnName, $postType) |
56 | { |
57 | if ($columnName !== 'beyondwords') { |
58 | return; |
59 | } |
60 | |
61 | $postTypes = SettingsUtils::getCompatiblePostTypes(); |
62 | |
63 | if (! in_array($postType, $postTypes)) { |
64 | return; |
65 | } |
66 | |
67 | wp_nonce_field('beyondwords_bulk_edit_nonce', 'beyondwords_bulk_edit'); |
68 | |
69 | ?> |
70 | <fieldset class="inline-edit-col-right"> |
71 | <div class="inline-edit-col"> |
72 | <div class="inline-edit-group wp-clearfix"> |
73 | <label class="alignleft"> |
74 | <span class="title"><?php esc_html_e('BeyondWords', 'speechkit'); ?></span> |
75 | <select name="beyondwords_generate_audio"> |
76 | <option value="-1"><?php esc_html_e('— No change —', 'speechkit'); ?></option> |
77 | <option value="generate"><?php esc_html_e('Generate audio', 'speechkit'); ?></option> |
78 | <option value="delete"><?php esc_html_e('Delete audio', 'speechkit'); ?></option> |
79 | </select> |
80 | </label> |
81 | </div> |
82 | </div> |
83 | </fieldset> |
84 | <?php |
85 | } |
86 | |
87 | /** |
88 | * Save Bulk Edit updates. |
89 | * |
90 | * @link https://rudrastyh.com/wordpress/bulk-edit.html |
91 | */ |
92 | public function saveBulkEdit() |
93 | { |
94 | /* |
95 | * We need to verify this came from the our screen and with proper authorization, |
96 | * because save_post can be triggered at other times. |
97 | */ |
98 | if ( |
99 | ! isset($_POST['beyondwords_bulk_edit_nonce']) || |
100 | ! wp_verify_nonce(sanitize_key($_POST['beyondwords_bulk_edit_nonce']), 'beyondwords_bulk_edit') |
101 | ) { |
102 | wp_nonce_ays(''); |
103 | } |
104 | |
105 | if (! isset($_POST['beyondwords_bulk_edit']) || ! isset($_POST['post_ids'])) { |
106 | return []; |
107 | } |
108 | |
109 | if (is_array($_POST['post_ids']) && count($_POST['post_ids'])) { |
110 | $postIds = array_map('intval', $_POST['post_ids']); |
111 | $postIds = array_filter($postIds); |
112 | |
113 | switch ($_POST['beyondwords_bulk_edit']) { |
114 | case 'generate': |
115 | return $this->generateAudioForPosts($postIds); |
116 | break; |
117 | case 'delete': |
118 | return $this->deleteAudioForPosts($postIds); |
119 | break; |
120 | } |
121 | } |
122 | |
123 | return []; |
124 | } |
125 | |
126 | public function generateAudioForPosts($postIds) |
127 | { |
128 | if (! is_array($postIds)) { |
129 | return false; |
130 | } |
131 | |
132 | $updatedPostIds = []; |
133 | |
134 | foreach ($postIds as $postId) { |
135 | if (! get_post_meta($postId, 'beyondwords_content_id', true)) { |
136 | update_post_meta($postId, 'beyondwords_generate_audio', '1'); |
137 | } |
138 | $updatedPostIds[] = $postId; |
139 | } |
140 | |
141 | return $updatedPostIds; |
142 | } |
143 | |
144 | /** |
145 | * @SuppressWarnings(PHPMD.LongVariable) |
146 | */ |
147 | public function deleteAudioForPosts($postIds) |
148 | { |
149 | global $beyondwords_wordpress_plugin; |
150 | |
151 | if (! is_array($postIds)) { |
152 | return false; |
153 | } |
154 | |
155 | $updatedPostIds = []; |
156 | |
157 | $response = $beyondwords_wordpress_plugin->core->batchDeleteAudioForPosts($postIds); |
158 | |
159 | if (! $response) { |
160 | throw new \Exception(esc_html__('Error while bulk deleting audio. Please contact support with reference BULK-NO-RESPONSE.', 'speechkit')); // phpcs:ignore Generic.Files.LineLength.TooLong |
161 | } |
162 | |
163 | // Now process all posts |
164 | $keys = CoreUtils::getPostMetaKeys('all'); |
165 | |
166 | foreach ($response as $postId) { |
167 | foreach ($keys as $key) { |
168 | delete_post_meta($postId, $key); |
169 | } |
170 | $updatedPostIds[] = $postId; |
171 | } |
172 | |
173 | return $updatedPostIds; |
174 | } |
175 | |
176 | /** |
177 | * |
178 | */ |
179 | public function bulkActionsEdit($bulk_array) |
180 | { |
181 | $bulk_array['beyondwords_generate_audio'] = __('Generate audio', 'speechkit'); |
182 | $bulk_array['beyondwords_delete_audio'] = __('Delete audio', 'speechkit'); |
183 | |
184 | return $bulk_array; |
185 | } |
186 | |
187 | /** |
188 | * @SuppressWarnings(PHPMD.LongVariable) |
189 | */ |
190 | public function handleBulkGenerateAction($redirect, $doaction, $objectIds) |
191 | { |
192 | if ($doaction !== 'beyondwords_generate_audio') { |
193 | return $redirect; |
194 | } |
195 | |
196 | global $beyondwords_wordpress_plugin; |
197 | |
198 | // Remove query args |
199 | $args = [ |
200 | 'beyondwords_bulk_generated', |
201 | 'beyondwords_bulk_deleted', |
202 | 'beyondwords_bulk_failed', |
203 | 'beyondwords_bulk_error', |
204 | ]; |
205 | |
206 | $redirect = remove_query_arg($args, $redirect); |
207 | |
208 | // Order batch by Post ID asc |
209 | sort($objectIds); |
210 | |
211 | $generated = 0; |
212 | $failed = 0; |
213 | |
214 | try { |
215 | // Update all custom fields before attempting any processing |
216 | foreach ($objectIds as $postId) { |
217 | update_post_meta($postId, 'beyondwords_generate_audio', '1'); |
218 | } |
219 | |
220 | // Now process all posts |
221 | foreach ($objectIds as $postId) { |
222 | if ( |
223 | $beyondwords_wordpress_plugin instanceof Plugin |
224 | && $beyondwords_wordpress_plugin->core instanceof Core |
225 | ) { |
226 | $response = $beyondwords_wordpress_plugin->core->generateAudioForPost($postId); |
227 | |
228 | if ($response) { |
229 | $generated++; |
230 | } else { |
231 | $failed++; |
232 | } |
233 | } else { |
234 | throw new \Exception(esc_html__('Error while bulk generating audio. Please contact support with reference BULK-NO-PLUGIN.', 'speechkit')); // phpcs:ignore Generic.Files.LineLength.TooLong |
235 | } |
236 | } |
237 | } catch (\Exception $e) { |
238 | $redirect = add_query_arg('beyondwords_bulk_error', $e->getMessage(), $redirect); |
239 | } |
240 | |
241 | // Add $generated & $failed query args into redirect |
242 | $redirect = add_query_arg('beyondwords_bulk_generated', $generated, $redirect); |
243 | $redirect = add_query_arg('beyondwords_bulk_failed', $failed, $redirect); |
244 | |
245 | // Add nonce to redirect url |
246 | $nonce = wp_create_nonce('beyondwords_bulk_edit_result'); |
247 | $redirect = add_query_arg('beyondwords_bulk_edit_result_nonce', $nonce, $redirect); |
248 | |
249 | return $redirect; |
250 | } |
251 | |
252 | /** |
253 | * |
254 | */ |
255 | public function handleBulkDeleteAction($redirect, $doaction, $objectIds) |
256 | { |
257 | if ($doaction !== 'beyondwords_delete_audio') { |
258 | return $redirect; |
259 | } |
260 | |
261 | // Remove query args |
262 | $args = [ |
263 | 'beyondwords_bulk_generated', |
264 | 'beyondwords_bulk_deleted', |
265 | 'beyondwords_bulk_failed', |
266 | 'beyondwords_bulk_error', |
267 | ]; |
268 | |
269 | $redirect = remove_query_arg($args, $redirect); |
270 | |
271 | // Order batch by Post ID asc |
272 | sort($objectIds); |
273 | |
274 | $deleted = 0; |
275 | |
276 | // Handle "Delete audio" bulk action |
277 | try { |
278 | $result = $this->deleteAudioForPosts($objectIds); |
279 | |
280 | $deleted = count($result); |
281 | |
282 | // Add $deleted query arg into redirect |
283 | $redirect = add_query_arg('beyondwords_bulk_deleted', $deleted, $redirect); |
284 | } catch (\Exception $e) { |
285 | $redirect = add_query_arg('beyondwords_bulk_error', $e->getMessage(), $redirect); |
286 | } |
287 | |
288 | // Add $nonce query arg into redirect |
289 | $nonce = wp_create_nonce('beyondwords_bulk_edit_result'); |
290 | $redirect = add_query_arg('beyondwords_bulk_edit_result_nonce', $nonce, $redirect); |
291 | |
292 | return $redirect; |
293 | } |
294 | } |