PluginProbe
BeyondWords – AI audio for publishers / 4.2.4
BeyondWords – AI audio for publishers v4.2.4
7.1.0 trunk 4.0.0 4.0.1 4.0.2 4.0.3 4.0.4 4.0.5 4.0.6 4.1.0 4.1.1 4.1.2 4.2.0 4.2.1 4.2.2 4.2.3 4.2.4 4.3.0 4.4.0 4.5.0 4.5.1 4.6.0 4.6.1 4.6.2 4.7.0 All 43 releases
speechkit / src / Component / Posts / BulkEdit / BulkEdit.php

BulkEdit.php in BeyondWords – AI audio for publishers 4.2.4, at src/Component/Posts/BulkEdit/BulkEdit.php

426 lines 12.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
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 setup
24 *
25 * @since 3.0.0
26 */
27 class BulkEdit
28 {
29 /**
30 * Constructor
31 */
32 public function __construct()
33 {
34 add_action('bulk_edit_custom_box', array($this, 'bulkEditCustomBox'), 10, 2);
35 add_action('wp_ajax_save_bulk_edit_beyondwords', array($this, 'saveBulkEdit'));
36
37 add_action('admin_notices', array($this, 'deletedNotice'));
38 add_action('admin_notices', array($this, 'generatedNotice'));
39 add_action('admin_notices', array($this, 'failedNotice'));
40 add_action('admin_notices', array($this, 'errorNotice'));
41
42 add_action('wp_loaded', function () {
43 $postTypes = SettingsUtils::getSupportedPostTypes();
44
45 if (is_array($postTypes)) {
46 foreach ($postTypes as $postType) {
47 add_filter("bulk_actions-edit-{$postType}", array($this, 'bulkActionsEdit'), 10, 1);
48 add_filter("handle_bulk_actions-edit-{$postType}", array($this, 'handleBulkDeleteAction'), 10, 3);
49 add_filter("handle_bulk_actions-edit-{$postType}", array($this, 'handleBulkGenerateAction'), 10, 3);
50 }
51 }
52 });
53 }
54
55 /**
56 * Adds the meta box container.
57 */
58 public function bulkEditCustomBox($columnName, $postType)
59 {
60 if ($columnName !== 'beyondwords') {
61 return;
62 }
63
64 $postTypes = SettingsUtils::getSupportedPostTypes();
65
66 if (! in_array($postType, $postTypes)) {
67 return;
68 }
69
70 wp_nonce_field('beyondwords_bulk_edit_nonce', 'beyondwords_bulk_edit');
71
72 ?>
73 <fieldset class="inline-edit-col-right">
74 <div class="inline-edit-col">
75 <div class="inline-edit-group wp-clearfix">
76 <label class="alignleft">
77 <span class="title"><?php _e('BeyondWords', 'speechkit'); ?></span>
78 <select name="beyondwords_generate_audio">
79 <option value="-1"><?php _e('— No change —', 'speechkit'); ?></option>
80 <option value="generate"><?php _e('Generate audio', 'speechkit'); ?></option>
81 <option value="delete"><?php _e('Delete audio', 'speechkit'); ?></option>
82 </select>
83 </label>
84 </div>
85 </div>
86 </fieldset>
87 <?php
88 }
89
90 /**
91 * Save Bulk Edit updates.
92 *
93 * @link https://rudrastyh.com/wordpress/bulk-edit.html
94 */
95 public function saveBulkEdit()
96 {
97 /*
98 * We need to verify this came from the our screen and with proper authorization,
99 * because save_post can be triggered at other times.
100 */
101 if (
102 ! isset($_POST['beyondwords_bulk_edit_nonce']) ||
103 ! wp_verify_nonce(sanitize_text_field($_POST['beyondwords_bulk_edit_nonce']), 'beyondwords_bulk_edit')
104 ) {
105 wp_nonce_ays('');
106 }
107
108 $action = filter_input(INPUT_POST, 'beyondwords_bulk_edit', FILTER_SANITIZE_FULL_SPECIAL_CHARS);
109 $postIds = filter_input(INPUT_POST, 'post_ids', FILTER_VALIDATE_INT, FILTER_REQUIRE_ARRAY);
110
111 switch ($action) {
112 case 'generate':
113 return $this->generateAudioForPosts($postIds);
114 break;
115 case 'delete':
116 return $this->deleteAudioForPosts($postIds);
117 break;
118 }
119
120 return [];
121 }
122
123 public function generateAudioForPosts($postIds)
124 {
125 if (! is_array($postIds)) {
126 return false;
127 }
128
129 $updatedPostIds = [];
130
131 foreach ($postIds as $postId) {
132 if (! get_post_meta($postId, 'beyondwords_content_id', true)) {
133 update_post_meta($postId, 'beyondwords_generate_audio', '1');
134 }
135 $updatedPostIds[] = $postId;
136 }
137
138 return $updatedPostIds;
139 }
140
141 /**
142 * @SuppressWarnings(PHPMD.LongVariable)
143 */
144 public function deleteAudioForPosts($postIds)
145 {
146 global $beyondwords_wordpress_plugin;
147
148 if (! is_array($postIds)) {
149 return false;
150 }
151
152 $updatedPostIds = [];
153
154 $response = $beyondwords_wordpress_plugin->core->batchDeleteAudioForPosts($postIds);
155
156 if (! $response) {
157 throw new \Exception('Error while bulk deleting audio. Please contact support with reference BULK-NO-RESPONSE.'); // phpcs:ignore
158 }
159
160 // Now process all posts
161 $keys = CoreUtils::getPostMetaKeys('all');
162
163 foreach ($response as $postId) {
164 foreach ($keys as $key) {
165 delete_post_meta($postId, $key);
166 }
167 $updatedPostIds[] = $postId;
168 }
169
170 return $updatedPostIds;
171 }
172
173 /**
174 *
175 */
176 public function bulkActionsEdit($bulk_array)
177 {
178 $bulk_array['beyondwords_generate_audio'] = __('Generate audio', 'speechkit');
179 $bulk_array['beyondwords_delete_audio'] = __('Delete audio', 'speechkit');
180
181 return $bulk_array;
182 }
183
184 /**
185 * @SuppressWarnings(PHPMD.LongVariable)
186 */
187 public function handleBulkGenerateAction($redirect, $doaction, $objectIds)
188 {
189 if ($doaction !== 'beyondwords_generate_audio') {
190 return $redirect;
191 }
192
193 global $beyondwords_wordpress_plugin;
194
195 // Remove query args
196 $args = [
197 'beyondwords_bulk_generated',
198 'beyondwords_bulk_deleted',
199 'beyondwords_bulk_failed',
200 'beyondwords_bulk_error',
201 ];
202
203 $redirect = remove_query_arg($args, $redirect);
204
205 // Order batch by Post ID asc
206 sort($objectIds);
207
208 $generated = 0;
209 $failed = 0;
210
211 try {
212 // Update all custom fields before attempting any processing
213 foreach ($objectIds as $postId) {
214 update_post_meta($postId, 'beyondwords_generate_audio', '1');
215 }
216
217 // Now process all posts
218 foreach ($objectIds as $postId) {
219 if (
220 $beyondwords_wordpress_plugin instanceof Plugin
221 && $beyondwords_wordpress_plugin->core instanceof Core
222 ) {
223 $response = $beyondwords_wordpress_plugin->core->generateAudioForPost($postId);
224
225 if ($response) {
226 $generated++;
227 } else {
228 $failed++;
229 }
230 } else {
231 throw new \Exception('Error while bulk generating audio. Please contact support with reference BULK-NO-PLUGIN.'); // phpcs:ignore
232 }
233 }
234 } catch (\Exception $e) {
235 $redirect = add_query_arg('beyondwords_bulk_error', $e->getMessage(), $redirect);
236 }
237
238 // Add $generated & $failed query args into redirect
239 $redirect = add_query_arg('beyondwords_bulk_generated', $generated, $redirect);
240 $redirect = add_query_arg('beyondwords_bulk_failed', $failed, $redirect);
241
242 // Add $nonce query arg into redirect
243 $nonce = wp_create_nonce('beyondwords_bulk_edit');
244 $redirect = add_query_arg('beyondwords_bulk_edit_nonce', $nonce, $redirect);
245
246 return $redirect;
247 }
248
249 /**
250 *
251 */
252 public function handleBulkDeleteAction($redirect, $doaction, $objectIds)
253 {
254 if ($doaction !== 'beyondwords_delete_audio') {
255 return $redirect;
256 }
257
258 // Remove query args
259 $args = [
260 'beyondwords_bulk_generated',
261 'beyondwords_bulk_deleted',
262 'beyondwords_bulk_failed',
263 'beyondwords_bulk_error',
264 ];
265
266 $redirect = remove_query_arg($args, $redirect);
267
268 // Order batch by Post ID asc
269 sort($objectIds);
270
271 $deleted = 0;
272
273 // Handle "Delete audio" bulk action
274 try {
275 $result = $this->deleteAudioForPosts($objectIds);
276
277 $deleted = count($result);
278
279 // Add $deleted query arg into redirect
280 $redirect = add_query_arg('beyondwords_bulk_deleted', $deleted, $redirect);
281 } catch (\Exception $e) {
282 $redirect = add_query_arg('beyondwords_bulk_error', $e->getMessage(), $redirect);
283 }
284
285 // Add $nonce query arg into redirect
286 $nonce = wp_create_nonce('beyondwords_bulk_edit');
287 $redirect = add_query_arg('beyondwords_bulk_edit_nonce', $nonce, $redirect);
288
289 return $redirect;
290 }
291
292 /**
293 * @since 4.1.0
294 */
295 public function generatedNotice()
296 {
297 if (! isset($_REQUEST['beyondwords_bulk_edit_nonce'])) {
298 return;
299 }
300
301 if (! wp_verify_nonce(sanitize_text_field($_REQUEST['beyondwords_bulk_edit_nonce']), 'beyondwords_bulk_edit')) {
302 wp_nonce_ays('');
303 }
304
305 $count = filter_input(INPUT_GET, 'beyondwords_bulk_generated', FILTER_SANITIZE_NUMBER_INT);
306
307 if ($count) {
308 $message = sprintf(
309 /* translators: %d is replaced with the number of posts processed */
310 _n(
311 'Audio was requested for %d post.',
312 'Audio was requested for %d posts.',
313 $count,
314 'speechkit'
315 ),
316 $count
317 );
318 ?>
319 <div class="notice notice-info is-dismissible">
320 <p>
321 <?php echo esc_html($message); ?>
322 </p>
323 </div>
324 <?php
325 }
326 }
327
328 /**
329 *
330 */
331 public function deletedNotice()
332 {
333 if (! isset($_REQUEST['beyondwords_bulk_edit_nonce'])) {
334 return;
335 }
336
337 if (! wp_verify_nonce(sanitize_text_field($_REQUEST['beyondwords_bulk_edit_nonce']), 'beyondwords_bulk_edit')) {
338 wp_nonce_ays('');
339 }
340
341 $count = filter_input(INPUT_GET, 'beyondwords_bulk_deleted', FILTER_SANITIZE_NUMBER_INT);
342
343 if ($count) {
344 $message = sprintf(
345 /* translators: %d is replaced with the number of posts processed */
346 _n(
347 'Audio was deleted for %d post.',
348 'Audio was deleted for %d posts.',
349 $count,
350 'speechkit'
351 ),
352 $count
353 );
354 ?>
355 <div class="notice notice-info is-dismissible">
356 <p>
357 <?php echo esc_html($message); ?>
358 </p>
359 </div>
360 <?php
361 }
362 }
363
364 /**
365 *
366 */
367 public function failedNotice()
368 {
369 if (! isset($_REQUEST['beyondwords_bulk_edit_nonce'])) {
370 return;
371 }
372
373 if (! wp_verify_nonce(sanitize_text_field($_REQUEST['beyondwords_bulk_edit_nonce']), 'beyondwords_bulk_edit')) {
374 wp_nonce_ays('');
375 }
376
377 $count = filter_input(INPUT_GET, 'beyondwords_bulk_failed', FILTER_SANITIZE_NUMBER_INT);
378
379 if ($count) {
380 $message = sprintf(
381 /* translators: %d is replaced with the number of posts that were skipped */
382 _n(
383 '%d post failed, check for errors in the BeyondWords column below.',
384 '%d posts failed, check for errors in the BeyondWords column below.',
385 $count,
386 'speechkit'
387 ),
388 $count
389 );
390 ?>
391 <div class="notice notice-error">
392 <p>
393 <?php echo esc_html($message); ?>
394 </p>
395 </div>
396 <?php
397 }
398 }
399
400 /**
401 *
402 */
403 public function errorNotice()
404 {
405 if (! isset($_REQUEST['beyondwords_bulk_edit_nonce'])) {
406 return;
407 }
408
409 if (! wp_verify_nonce(sanitize_text_field($_REQUEST['beyondwords_bulk_edit_nonce']), 'beyondwords_bulk_edit')) {
410 wp_nonce_ays('');
411 }
412
413 $message = filter_input(INPUT_GET, 'beyondwords_bulk_error', FILTER_SANITIZE_FULL_SPECIAL_CHARS);
414
415 if ($message) {
416 ?>
417 <div class="notice notice-error">
418 <p>
419 <?php echo esc_html($message); ?>
420 </p>
421 </div>
422 <?php
423 }
424 }
425 }
426