PluginProbe
Social Media Auto Poster – Schedule & Publish to Buffer / 6.2.0
Social Media Auto Poster – Schedule & Publish to Buffer v6.2.0
6.2.4 6.2.3 6.2.2 6.2.1 6.2.0 6.1.2 6.1.1 6.1.0 6.0.9 6.0.8 6.0.7 6.0.6 6.0.5 6.0.4 6.0.3 6.0.2 6.0.1 6.0.0 3.8.1 3.8.2 3.8.3 3.8.4 3.8.5 3.8.6 3.8.7 All 125 releases
wp-to-buffer / lib / social / includes / class-log.php

class-log.php in Social Media Auto Poster – Schedule & Publish to Buffer 6.2.0, at lib/social/includes/class-log.php

1,128 lines 30.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Log class.
4 *
5 * @package WPZinc\Social
6 * @author WP Zinc
7 */
8
9 namespace WPZinc\Social;
10
11 /**
12 * Handles logging and log output.
13 *
14 * @package WPZinc\Social
15 * @author WP Zinc
16 * @version 3.0.0
17 */
18 class Log {
19
20 /**
21 * Holds the base class object.
22 *
23 * @since 3.2.0
24 *
25 * @var object
26 */
27 public $base;
28
29 /**
30 * Holds the DB table name
31 *
32 * @since 3.9.6
33 *
34 * @var string
35 */
36 private $table;
37
38 /**
39 * Holds items added to the debug log using add_to_debug_log(),
40 *
41 * @since 4.1.8
42 *
43 * @var array
44 */
45 private $debug_log = array();
46
47 /**
48 * Constructor
49 *
50 * @since 3.0.0
51 *
52 * @param object $base Base Plugin Class.
53 */
54 public function __construct( $base ) {
55
56 // Store base class.
57 $this->base = $base;
58
59 // Define the database table name.
60 $this->table = 'to_' . strtolower( $this->base->plugin->account ) . '_log';
61
62 // Actions.
63 add_filter( 'set-screen-option', array( $this, 'set_screen_options' ), 10, 3 );
64 add_action( 'current_screen', array( $this, 'run_log_table_bulk_actions' ) );
65 add_action( 'current_screen', array( $this, 'run_log_table_filters' ) );
66 add_action( 'admin_menu', array( $this, 'admin_meta_boxes' ) );
67 add_action( 'wp_loaded', array( $this, 'export' ) );
68
69 }
70
71 /**
72 * Activation routines for this Model
73 *
74 * @since 3.9.6
75 *
76 * @global $wpdb WordPress DB Object
77 */
78 public function activate() {
79
80 global $wpdb;
81
82 // Enable error output if WP_DEBUG is enabled.
83 $wpdb->show_errors = true;
84
85 // Create database table.
86 $query = $wpdb->prepare(
87 "CREATE TABLE IF NOT EXISTS %i (
88 `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
89 `post_id` int(11) NOT NULL,
90 `action` enum('publish','update','repost','bulk_publish') DEFAULT NULL,
91 `request_sent` datetime NOT NULL,
92 `profile_id` varchar(191) NOT NULL,
93 `profile_name` varchar(191) NOT NULL DEFAULT '',
94 `result` enum('success','test','pending','warning','error') NOT NULL DEFAULT 'success',
95 `result_message` text,
96 `status_text` text,
97 `status_created_at` datetime DEFAULT NULL,
98 `status_due_at` datetime DEFAULT NULL,
99 PRIMARY KEY (`id`),
100 KEY `post_id` (`post_id`),
101 KEY `action` (`action`),
102 KEY `result` (`result`),
103 KEY `profile_id` (`profile_id`)
104 )",
105 $wpdb->prefix . $this->table
106 );
107 $query .= ' ' . $wpdb->get_charset_collate() . ' AUTO_INCREMENT=1';
108 $wpdb->query( $query ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
109
110 }
111
112 /**
113 * Checks if the log is enabled
114 *
115 * @since 4.2.0
116 *
117 * @return bool Logging Enabled
118 */
119 public function is_enabled() {
120
121 // Get Log Settings.
122 $log_settings = $this->base->get_class( 'settings' )->get_option( 'log', false );
123
124 // Logging disabled if no settings.
125 if ( ! $log_settings ) {
126 return false;
127 }
128
129 // Logging disabled if no setting.
130 if ( ! isset( $log_settings['enabled'] ) ) {
131 return false;
132 }
133
134 // Return.
135 return absint( $log_settings['enabled'] );
136
137 }
138
139 /**
140 * Sets values for options displayed in the Screen Options dropdown on the Logs
141 * WP_List_Table
142 *
143 * @since 4.3.0
144 *
145 * @param mixed $screen_option The value to save instead of the option value. Default false (to skip saving the current option).
146 * @param string $option The option name.
147 * @param string $value The option value.
148 * @return string The option value
149 */
150 public function set_screen_options( $screen_option, $option, $value ) { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter
151
152 return $value;
153
154 }
155
156 /**
157 * Defines options to display in the Screen Options dropdown on the Logs
158 * WP_List_Table
159 *
160 * @since 4.3.0
161 */
162 public function add_screen_options() {
163
164 add_screen_option(
165 'per_page',
166 array(
167 'label' => __( 'Log Entries per Page', 'wp-to-buffer' ),
168 'default' => 20,
169 'option' => $this->base->plugin->filter_name . '_logs_per_page',
170 )
171 );
172
173 // Initialize Logs WP_List_Table, as this will trigger WP_List_Table to add column options.
174 $log_table = new \WPZinc\Social\Log_Table( $this->base );
175
176 }
177
178 /**
179 * Run any bulk actions on the Log WP_List_Table
180 *
181 * @since 3.9.6
182 */
183 public function run_log_table_bulk_actions() {
184
185 // Get screen.
186 $screen = $this->base->get_class( 'screen' )->get_current_screen();
187
188 // Bail if we're not on the Log screen.
189 if ( $screen['screen'] !== 'log' ) {
190 return;
191 }
192
193 // Bail if nonce is not valid.
194 if ( ! isset( $_REQUEST['_wpnonce'] ) || ! wp_verify_nonce( sanitize_key( wp_unslash( $_REQUEST['_wpnonce'] ) ), 'bulk-wpzinc-social-log' ) ) {
195 return;
196 }
197
198 // Get bulk action from the fields that might contain it.
199 $bulk_action = array_values(
200 array_filter(
201 array(
202 ( isset( $_REQUEST['bulk_action'] ) && $_REQUEST['bulk_action'] != -1 ? sanitize_text_field( wp_unslash( $_REQUEST['bulk_action'] ) ) : '' ), // phpcs:ignore Universal.Operators.StrictComparisons.LooseNotEqual
203 ( isset( $_REQUEST['bulk_action2'] ) && $_REQUEST['bulk_action2'] != -1 ? sanitize_text_field( wp_unslash( $_REQUEST['bulk_action2'] ) ) : '' ), // phpcs:ignore Universal.Operators.StrictComparisons.LooseNotEqual
204 ( isset( $_REQUEST['bulk_action3'] ) && ! empty( $_REQUEST['bulk_action3'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['bulk_action3'] ) ) : '' ),
205 )
206 )
207 );
208
209 // Bail if no bulk action.
210 if ( ! is_array( $bulk_action ) ) {
211 return;
212 }
213 if ( ! count( $bulk_action ) ) {
214 return;
215 }
216
217 // Setup notices class, enabling persistent storage.
218 $this->base->get_class( 'notices' )->enable_store();
219 $this->base->get_class( 'notices' )->set_key_prefix( $this->base->plugin->filter_name . '_' . wp_get_current_user()->ID );
220
221 // Perform Bulk Action.
222 switch ( $bulk_action[0] ) {
223 /**
224 * Delete Logs
225 */
226 case 'delete':
227 // Get Post IDs.
228 if ( ! isset( $_REQUEST['ids'] ) ) {
229 $this->base->get_class( 'notices' )->add_error_notice(
230 __( 'No logs were selected for deletion.', 'wp-to-buffer' )
231 );
232 break;
233 }
234
235 // Delete Logs by IDs.
236 $ids = array_unique( array_map( 'absint', $_REQUEST['ids'] ) );
237 $this->delete_by_ids( $ids );
238
239 // Add success notice.
240 $this->base->get_class( 'notices' )->add_success_notice(
241 sprintf(
242 /* translators: Number of log entries deleted */
243 __( '%s Logs deleted.', 'wp-to-buffer' ),
244 count( $ids )
245 )
246 );
247 break;
248
249 /**
250 * Delete All Logs
251 */
252 case 'delete_all':
253 // Delete Logs.
254 $this->delete_all();
255
256 // Add success notice.
257 $this->base->get_class( 'notices' )->add_success_notice(
258 __( 'All Logs deleted.', 'wp-to-buffer' )
259 );
260 break;
261
262 }
263
264 // Redirect.
265 wp_safe_redirect( 'admin.php?page=' . $this->base->plugin->name . '-' . $screen['screen'] );
266 die();
267
268 }
269
270 /**
271 * Redirect POST filters to a GET URL
272 *
273 * @since 3.9.6
274 */
275 public function run_log_table_filters() {
276
277 // Get screen.
278 $screen = $this->base->get_class( 'screen' )->get_current_screen();
279
280 // Bail if we're not on the Log screen.
281 if ( $screen['screen'] !== 'log' ) {
282 return;
283 }
284
285 // Bail if nonce is not valid.
286 if ( ! isset( $_REQUEST['_wpnonce'] ) || ! wp_verify_nonce( sanitize_key( wp_unslash( $_REQUEST['_wpnonce'] ) ), 'bulk-wpzinc-social-log' ) ) {
287 return;
288 }
289
290 $params = array();
291 foreach ( $this->base->get_class( 'common' )->get_log_filters() as $filter ) {
292 if ( ! isset( $_POST[ $filter ] ) ) {
293 continue;
294 }
295 if ( empty( $_POST[ $filter ] ) ) {
296 continue;
297 }
298
299 $params[ $filter ] = sanitize_text_field( wp_unslash( $_POST[ $filter ] ) );
300 }
301
302 // Include search parameter.
303 if ( array_key_exists( 's', $_POST ) ) {
304 $params['s'] = sanitize_text_field( wp_unslash( $_POST['s'] ) );
305 }
306
307 // If params don't exist, exit.
308 if ( ! count( $params ) ) {
309 return;
310 }
311
312 // Add nonce.
313 $params['_wpnonce'] = wp_create_nonce( 'bulk-wpzinc-social-log' );
314
315 // Redirect.
316 wp_safe_redirect( 'admin.php?page=' . $this->base->plugin->name . '-' . $screen['screen'] . '&' . http_build_query( $params ) );
317 die();
318
319 }
320
321 /**
322 * Adds Metaboxes to Post Edit Screens
323 *
324 * @since 3.0.0
325 */
326 public function admin_meta_boxes() {
327
328 // Only load if Logging is enabled and Displayed on Posts.
329 $log_enabled = $this->is_enabled();
330 $log_display_on_posts = $this->base->get_class( 'settings' )->get_setting( 'log', '[display_on_posts]' );
331
332 if ( ! $log_enabled ) {
333 return;
334 }
335 if ( ! $log_display_on_posts ) {
336 return;
337 }
338
339 // Check if we need to hide the meta box by the logged in User's role.
340 if ( wp_get_current_user() && is_array( wp_get_current_user()->roles ) && ! empty( wp_get_current_user()->roles ) ) {
341 // Bail if we're hiding the meta boxes for the logged in User's role.
342 if ( $this->base->get_class( 'settings' )->get_setting( 'hide_meta_box_by_roles', '[' . wp_get_current_user()->roles[0] . ']' ) ) {
343 return;
344 }
345 }
346
347 // Get Post Types.
348 $post_types = $this->base->get_class( 'common' )->get_post_types();
349
350 // Add meta boxes for each Post Type.
351 foreach ( $post_types as $post_type => $post_type_obj ) {
352 add_meta_box(
353 $this->base->plugin->name . '-log',
354 sprintf(
355 /* translators: Social Media Service Name (Buffer, Hootsuite) */
356 __( '%s Log', 'wp-to-buffer' ),
357 $this->base->plugin->displayName
358 ),
359 array( $this, 'output_post_log' ),
360 $post_type,
361 'normal',
362 'low'
363 );
364 }
365
366 }
367
368 /**
369 * Outputs the plugin's log of existing status update calls made to the API
370 *
371 * @since 3.0.0
372 *
373 * @param WP_Post $post Post.
374 */
375 public function output_post_log( $post ) {
376
377 // Get log.
378 $log = $this->get( $post->ID );
379
380 // Define URLs.
381 $urls = array(
382 'refresh' => add_query_arg( array( $this->base->plugin->name . '-refresh-log' => 1 ), get_edit_post_link( $post->ID ) ),
383 'export' => add_query_arg( array( $this->base->plugin->name . '-export-log' => wp_create_nonce( $this->base->plugin->name . '-export-log' ) ), get_edit_post_link( $post->ID ) ),
384 'clear' => add_query_arg( array( $this->base->plugin->name . '-clear-log' => 1 ), get_edit_post_link( $post->ID ) ),
385 );
386
387 // Load View.
388 include_once $this->base->plugin->folder . 'lib/social/views/post-log.php';
389
390 }
391
392 /**
393 * Exports a Post's API log file in JSON format
394 *
395 * @since 3.0.0
396 */
397 public function export() {
398
399 // Bail if nonce is not valid.
400 if ( ! isset( $_REQUEST[ $this->base->plugin->name . '-export-log' ] ) || ! wp_verify_nonce( sanitize_key( wp_unslash( $_REQUEST[ $this->base->plugin->name . '-export-log' ] ) ), $this->base->plugin->name . '-export-log' ) ) {
401 return;
402 }
403
404 // Bail if no post specified.
405 if ( ! isset( $_GET['post'] ) ) {
406 return;
407 }
408
409 // Check the user is logged in and can edit posts in order to access the log.
410 if ( ! function_exists( 'current_user_can' ) ) {
411 return;
412 }
413 if ( ! current_user_can( 'edit_post', absint( $_GET['post'] ) ) ) {
414 return;
415 }
416
417 // Get log.
418 $log = $this->get( absint( $_GET['post'] ) );
419
420 // Build JSON.
421 $json = wp_json_encode( $log );
422
423 // Export.
424 header( 'Content-type: application/x-msdownload' );
425 header( 'Content-Disposition: attachment; filename=log.json' );
426 header( 'Pragma: no-cache' );
427 header( 'Expires: 0' );
428 echo $json; // phpcs:ignore WordPress.Security.EscapeOutput
429 exit();
430
431 }
432
433 /**
434 * Adds a log entry for the given Post ID
435 *
436 * @since 3.9.6
437 *
438 * @param int $post_id Post ID.
439 * @param array $log Log.
440 * enum $action Action (publish,update,repost,bulk_publish).
441 * datetime $request_sent Request Sent to API.
442 * string $profile_id Profile ID.
443 * string $profile_name Profile Name.
444 * enum $result Result (success,test_mode,pending,error).
445 * string $result_message Result Message.
446 * string $status_text Status Text.
447 * datetime $status_created_at Status Created At on API.
448 * datetime $status_due_at Status Scheduled for Publication to Profile.
449 */
450 public function add( $post_id, $log ) {
451
452 global $wpdb;
453
454 // Fetch Log Levels that are enabled in the Plugin Settings.
455 $log_levels = $this->base->get_class( 'settings' )->get_setting( 'log', '[log_level]' );
456
457 // Bail if the Log Result doesn't match a level that we're saving to the log table.
458 if ( ! in_array( $log['result'], $log_levels, true ) ) {
459 return;
460 }
461
462 // Enable error output if WP_DEBUG is enabled.
463 $wpdb->show_errors();
464
465 // Add Post ID to log.
466 $log['post_id'] = absint( $post_id );
467
468 // Insert Log.
469 $result = $wpdb->insert(
470 $wpdb->prefix . $this->table,
471 $log
472 );
473
474 }
475
476 /**
477 * Retrieves the log for the given Post ID
478 *
479 * @since 3.0.0
480 *
481 * @param int $post_id Post ID.
482 * @return array Log
483 */
484 public function get( $post_id ) {
485
486 global $wpdb;
487
488 // Get log.
489 $log = $wpdb->get_results(
490 $wpdb->prepare(
491 'SELECT * FROM %i WHERE post_id = %d ORDER BY id DESC',
492 $wpdb->prefix . $this->table,
493 absint( $post_id )
494 ),
495 ARRAY_A
496 );
497
498 /**
499 * Filters the log entries before output.
500 *
501 * @since 3.0.0
502 *
503 * @param array $log Post Log.
504 * @param int $post_id Post ID.
505 */
506 $log = apply_filters( $this->base->plugin->filter_name . '_get_log', $log, $post_id );
507
508 // Return.
509 return $log;
510
511 }
512
513 /**
514 * Returns key/value Profile ID and Name pairs based on all unique
515 * Profile IDs in the Log table
516 *
517 * @since 3.9.6
518 *
519 * @return array
520 */
521 public function get_profile_id_names() {
522
523 global $wpdb;
524
525 $results = $wpdb->get_results(
526 $wpdb->prepare(
527 'SELECT profile_id, profile_name FROM %i GROUP BY profile_id ORDER BY profile_name DESC',
528 $wpdb->prefix . $this->table
529 ),
530 ARRAY_A
531 );
532
533 if ( ! $results || ! count( $results ) ) {
534 return array();
535 }
536
537 $profiles = array();
538 foreach ( $results as $result ) {
539 if ( empty( $result['profile_id'] ) ) {
540 continue;
541 }
542 $profiles[ $result['profile_id'] ] = ( empty( $result['profile_name'] ) ? __( 'Unknown', 'wp-to-buffer' ) : $result['profile_name'] );
543 }
544
545 return $profiles;
546
547 }
548
549 /**
550 * Defines the available Log Result Options
551 *
552 * @since 4.2.0
553 *
554 * @return array Result Options (success,test,warning,error).
555 */
556 public function get_result_options() {
557
558 // Define log result options.
559 $result_options = array(
560 'success' => __( 'Success', 'wp-to-buffer' ),
561 'test' => __( 'Test', 'wp-to-buffer' ),
562 'warning' => __( 'Warning', 'wp-to-buffer' ),
563 'error' => __( 'Error', 'wp-to-buffer' ),
564 );
565
566 /**
567 * Defines the available result options
568 *
569 * @since 4.2.0
570 *
571 * @param array $result_options Result Options.
572 */
573 $result_options = apply_filters( $this->base->plugin->filter_name . '_log_get_result_options', $result_options );
574
575 // Return filtered results.
576 return $result_options;
577
578 }
579
580 /**
581 * Returns the available Log Levels
582 *
583 * @since 4.2.0
584 *
585 * @return array Log Levels
586 */
587 public function get_level_options() {
588
589 // Define log levels.
590 $log_levels = array(
591 'success' => __( 'Success', 'wp-to-buffer' ),
592 'test' => __( 'Tests', 'wp-to-buffer' ),
593 'pending' => __( 'Pending', 'wp-to-buffer' ),
594 'warning' => __( 'Warnings', 'wp-to-buffer' ),
595 'error' => __( 'Errors', 'wp-to-buffer' ),
596 );
597
598 /**
599 * Defines the available log levels
600 *
601 * @since 4.2.0
602 *
603 * @param array $log_levels Log Levels.
604 */
605 $log_levels = apply_filters( $this->base->plugin->filter_name . '_log_get_log_levels', $log_levels );
606
607 // Return filtered results.
608 return $log_levels;
609
610 }
611
612 /**
613 * Searches logs by the given key/value pairs
614 *
615 * @since 3.9.6
616 *
617 * @param string $order_by Order Results By.
618 * @param string $order Order (asc|desc).
619 * @param int $page Pagination Offset (default: 0).
620 * @param int $per_page Number of Results to Return (default: 20).
621 * @param mixed $params Query Parameters (false = all records).
622 * @return array Log entries
623 */
624 public function search( $order_by, $order, $page = 0, $per_page = 20, $params = false ) {
625
626 global $wpdb;
627
628 // Build where clauses.
629 $where = $this->build_where_clause( $params );
630
631 // Prepare query.
632 $query = $wpdb->prepare(
633 'SELECT * FROM %i
634 LEFT JOIN %i
635 ON %i.post_id = %i.ID',
636 $wpdb->prefix . $this->table,
637 $wpdb->posts,
638 $wpdb->prefix . $this->table,
639 $wpdb->posts
640 );
641
642 // Add where clauses.
643 if ( $where !== false ) {
644 $query .= ' WHERE ' . $where;
645 }
646
647 // Order.
648 $query .= $wpdb->prepare(
649 ' ORDER BY %i.%i',
650 $wpdb->prefix . $this->table,
651 $order_by
652 );
653 $query .= ' ' . ( strtolower( $order ) === 'asc' ? 'ASC' : 'DESC' );
654
655 // Limit.
656 if ( $page > 0 && $per_page > 0 ) {
657 $query .= $wpdb->prepare( ' LIMIT %d, %d', ( ( $page - 1 ) * $per_page ), $per_page );
658 }
659
660 // Run and return query results.
661 return $wpdb->get_results( $query, ARRAY_A ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
662
663 }
664
665 /**
666 * Gets the number of log records found for the given query parameters
667 *
668 * @since 3.9.6
669 *
670 * @param mixed $params Query Parameters (false = all records).
671 * @return int Total Records
672 */
673 public function total( $params = false ) {
674
675 global $wpdb;
676
677 // Build where clauses.
678 $where = $this->build_where_clause( $params );
679
680 // Prepare query.
681 $query = $wpdb->prepare(
682 'SELECT COUNT(%i.id) FROM %i
683 LEFT JOIN %i
684 ON %i.post_id = %i.ID',
685 $wpdb->prefix . $this->table,
686 $wpdb->prefix . $this->table,
687 $wpdb->posts,
688 $wpdb->prefix . $this->table,
689 $wpdb->posts
690 );
691
692 // Add where clauses.
693 if ( $where !== false ) {
694 $query .= ' WHERE ' . $where;
695 }
696
697 // Run and return total records found.
698 return $wpdb->get_var( $query ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
699
700 }
701
702 /**
703 * Builds a WHERE SQL clause based on the given column key/values
704 *
705 * @since 3.9.6
706 *
707 * @param array $params Query Parameters (false = all records).
708 * @return string WHERE SQL clause
709 */
710 private function build_where_clause( $params ) {
711
712 global $wpdb;
713
714 // Bail if no params.
715 if ( ! $params ) {
716 return false;
717 }
718
719 // Build where clauses.
720 $where = array();
721 if ( $params !== false && is_array( $params ) && count( $params ) > 0 ) {
722 foreach ( $params as $key => $value ) {
723 // Skip blank params.
724 if ( empty( $value ) ) {
725 continue;
726 }
727
728 // Build condition based on the key.
729 switch ( $key ) {
730 case 'post_title':
731 $where[] = $wpdb->prepare(
732 '(%i LIKE %s OR status_text LIKE %s OR result_message LIKE %s)',
733 $key,
734 '%' . $wpdb->esc_like( $value ) . '%',
735 '%' . $wpdb->esc_like( $value ) . '%',
736 '%' . $wpdb->esc_like( $value ) . '%'
737 );
738 break;
739
740 case 'request_sent_start_date':
741 if ( ! empty( $params['request_sent_end_date'] ) && $params['request_sent_start_date'] > $params['request_sent_end_date'] ) {
742 $where[] = $wpdb->prepare(
743 'request_sent <= %s',
744 $value . ' 23:59:59'
745 );
746 } else {
747 $where[] = $wpdb->prepare(
748 'request_sent >= %s',
749 $value . ' 00:00:00'
750 );
751 }
752 break;
753
754 case 'request_sent_end_date':
755 if ( ! empty( $params['request_sent_start_date'] ) && $params['request_sent_start_date'] > $params['request_sent_end_date'] ) {
756 $where[] = $wpdb->prepare(
757 'request_sent >= %s',
758 $value . ' 00:00:00'
759 );
760 } else {
761 $where[] = $wpdb->prepare(
762 'request_sent <= %s',
763 $value . ' 23:59:59'
764 );
765 }
766 break;
767
768 default:
769 $where[] = $wpdb->prepare(
770 '%i = %s',
771 $key,
772 $value
773 );
774 break;
775 }
776 }
777 }
778
779 if ( ! count( $where ) ) {
780 return false;
781 }
782
783 return implode( ' AND ', $where );
784
785 }
786
787 /**
788 * Deletes a single Log entry for the given Log ID
789 *
790 * @since 3.9.6
791 *
792 * @param array $id Log ID.
793 * @return bool Success
794 */
795 public function delete_by_id( $id ) {
796
797 global $wpdb;
798
799 return $wpdb->delete(
800 $wpdb->prefix . $this->table,
801 array(
802 'id' => absint( $id ),
803 )
804 );
805
806 }
807
808 /**
809 * Deletes multiple Log entries for the given Log IDs
810 *
811 * @since 3.9.6
812 *
813 * @param array $ids Log IDs.
814 * @return bool Success
815 */
816 public function delete_by_ids( $ids ) {
817
818 global $wpdb;
819
820 return $wpdb->query(
821 $wpdb->prepare(
822 sprintf(
823 'DELETE FROM %s WHERE id IN (%s)',
824 $wpdb->prefix . $this->table, // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
825 implode( ',', array_fill( 0, count( $ids ), '%d' ) )
826 ),
827 $ids
828 )
829 );
830
831 }
832
833 /**
834 * Deletes Log entries for the given Post ID
835 *
836 * @since 3.7.9
837 *
838 * @param int $post_id Post ID.
839 * @return bool Success
840 */
841 public function delete_by_post_id( $post_id ) {
842
843 global $wpdb;
844
845 return $wpdb->delete(
846 $wpdb->prefix . $this->table,
847 array(
848 'post_id' => absint( $post_id ),
849 )
850 );
851
852 }
853
854 /**
855 * Deletes Log entries for the given Post ID and Pending Status
856 *
857 * @since 3.7.9
858 *
859 * @param int $post_id Post ID.
860 * @return bool Success
861 */
862 public function delete_pending_by_post_id( $post_id ) {
863
864 global $wpdb;
865
866 return $wpdb->delete(
867 $wpdb->prefix . $this->table,
868 array(
869 'post_id' => absint( $post_id ),
870 'result' => 'pending',
871 )
872 );
873 }
874
875 /**
876 * Deletes Log entries for the given Post ID and Action that have
877 * a pending Status
878 *
879 * @since 3.7.9
880 *
881 * @param int $post_id Post ID.
882 * @param string $action Action.
883 * @return bool Success
884 */
885 public function delete_pending_by_post_id_and_action( $post_id, $action = 'publish' ) {
886
887 global $wpdb;
888
889 return $wpdb->delete(
890 $wpdb->prefix . $this->table,
891 array(
892 'post_id' => absint( $post_id ),
893 'result' => 'pending',
894 'action' => $action,
895 )
896 );
897 }
898
899 /**
900 * Deletes all Log entries older than the given date
901 *
902 * @since 3.9.8
903 *
904 * @param datetime $date_time Date and Time.
905 * @return bool Success
906 */
907 public function delete_by_request_sent_cutoff( $date_time ) {
908
909 global $wpdb;
910
911 // Run query.
912 return $wpdb->query(
913 $wpdb->prepare(
914 'DELETE FROM %i WHERE request_sent < %s',
915 $wpdb->prefix . $this->table,
916 $date_time
917 )
918 );
919
920 }
921
922 /**
923 * Deletes all Log entries
924 *
925 * @since 3.9.6
926 *
927 * @return bool Success
928 */
929 public function delete_all() {
930
931 global $wpdb;
932
933 return $wpdb->query(
934 $wpdb->prepare(
935 'TRUNCATE TABLE %i',
936 $wpdb->prefix . $this->table
937 )
938 );
939
940 }
941
942 /**
943 * Wrapper for PHP's error_log() function, which will only write
944 * to the error log if:
945 * - WP_DEBUG = true
946 * - WP_DEBUG_DISPLAY = false
947 * - WP_DEBUG_LOG = true
948 *
949 * This will ensure that the output goes to wp-content/debug.log
950 *
951 * @since 3.6.8
952 *
953 * @param mixed $data Data to log.
954 * @param mixed $backtrace Backtrace data from debug_backtrace().
955 */
956 public function add_to_debug_log( $data = '', $backtrace = false ) {
957
958 // Add the data to our class array for possible output in the UI.
959 $this->debug_log[] = $data;
960
961 // Bail if Logging isn't enabled in the Plugin.
962 if ( ! $this->is_enabled() ) {
963 return;
964 }
965
966 // Bail if no WP_DEBUG, or it's false.
967 if ( ! defined( 'WP_DEBUG' ) || ! WP_DEBUG ) {
968 return;
969 }
970
971 // Bail if no WP_DEBUG_DISPLAY, or it's true.
972 if ( ! defined( 'WP_DEBUG_DISPLAY' ) || WP_DEBUG_DISPLAY ) {
973 return;
974 }
975
976 // Bail if no WP_DEBUG_LOG, or it's false.
977 if ( ! defined( 'WP_DEBUG_LOG' ) || ! WP_DEBUG_LOG ) {
978 return;
979 }
980
981 // If we need to fetch the class and function name to prefix to the log entry, do so now.
982 $prefix_data = '';
983 if ( $backtrace !== false ) {
984 if ( isset( $backtrace[0] ) ) {
985 if ( isset( $backtrace[0]['class'] ) ) {
986 $prefix_data .= $backtrace[0]['class'];
987 }
988 if ( isset( $backtrace[0]['function'] ) ) {
989 $prefix_data .= '::' . $backtrace[0]['function'] . '()';
990 }
991 }
992 }
993
994 // If the data is empty, change it to 'called'.
995 if ( empty( $data ) ) {
996 $data = 'Called';
997 }
998
999 // If the data is an array or object, convert it to a string.
1000 if ( is_array( $data ) || is_object( $data ) ) {
1001 $data = print_r( $data, true ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions
1002 }
1003
1004 // If we're prefixing the log entry, do so now.
1005 if ( ! empty( $prefix_data ) ) {
1006 $data = $prefix_data . ': ' . $data;
1007 }
1008
1009 // Add the data to the error log, which will appear in wp-content/debug.log.
1010 error_log( $data ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions
1011 }
1012
1013 /**
1014 * Returns contents of this class' debug_log array, which comprise of
1015 * items added using add_to_debug_log() above.
1016 *
1017 * @since 4.1.8
1018 *
1019 * @return array
1020 */
1021 public function get_debug_log() {
1022
1023 return $this->debug_log;
1024
1025 }
1026
1027 /**
1028 * Takes a given array of log results, and builds HTML table row output
1029 * that can be used by:
1030 * - Posts > Log Meta Box
1031 * - Bulk Publish > Results Screen
1032 *
1033 * @since 3.7.9
1034 *
1035 * @param array $log Log Results.
1036 * @param bool $is_wp_list_table Is Output for a WP_List_Table (adds checkbox and Post ID columns).
1037 * @param mixed $columns Displayed, Hidden and Sortable Columns (false = display all).
1038 * @return string Table Rows HTML
1039 */
1040 public function build_log_table_output( $log, $is_wp_list_table = false, $columns = false ) {
1041
1042 // Define columns.
1043 if ( is_array( $columns ) ) {
1044 list( $columns, $hidden, $sortable, $primary ) = $columns;
1045 $colspan = ( $is_wp_list_table ? 10 : 8 );
1046 } else {
1047 $columns = array();
1048 $hidden = array();
1049 $colspan = ( $is_wp_list_table ? 10 : 8 );
1050 }
1051
1052 // Define HTML output.
1053 $html = '';
1054
1055 // If no results, return a single row.
1056 if ( ! $log || ! is_array( $log ) || count( $log ) === 0 ) {
1057 $html = '
1058 <tr>
1059 <td colspan="' . $colspan . '">' .
1060 sprintf(
1061 /* translators: Social Media Service Name (Buffer, Hootsuite) */
1062 __( 'No log entries exist, or no status updates have been sent to %s.', 'wp-to-buffer' ),
1063 $this->base->plugin->account
1064 )
1065 .
1066 '</td>
1067 </tr>';
1068
1069 return $html;
1070 }
1071
1072 // Get Post Actions.
1073 $post_actions = $this->base->get_class( 'common' )->get_post_actions();
1074
1075 // Build Table HTML.
1076 foreach ( $log as $count => $result ) {
1077 // If output is for a WP_List_Table, add checkbox and Post ID.
1078 if ( $is_wp_list_table ) {
1079 $checkbox_id = '<th scope="row" class="check-column">
1080 <input type="checkbox" name="ids[' . $result['id'] . ']" value="' . $result['id'] . '" />
1081 </th>
1082 <td class="post_id column-post_id' . ( in_array( 'post_id', $hidden, true ) ? ' hidden' : '' ) . '">
1083 <a href="' . admin_url( 'admin.php?page=' . $this->base->plugin->name . '-log&s=' . $result['post_id'] ) . '">' .
1084 $result['post_id'] . '
1085 </a>
1086 </td>';
1087 }
1088
1089 // Add row to HTML.
1090 $html .= '
1091 <tr class="' . $result['result'] . ( ( $count % 2 > 0 ) ? ' alternate' : '' ) . '">
1092 ' . ( $is_wp_list_table ? $checkbox_id : '' ) . '
1093 <td class="request_sent column-request_sent' . ( in_array( 'request_sent', $hidden, true ) ? ' hidden' : '' ) . '">' . get_date_from_gmt( $result['request_sent'], get_option( 'date_format' ) . ' H:i:s' ) . '</td>
1094 <td class="action column-action' . ( in_array( 'action', $hidden, true ) ? ' hidden' : '' ) . '">' . ( isset( $post_actions[ $result['action'] ] ) ? $post_actions[ $result['action'] ] : '&nbsp;' ) . '</td>
1095 <td class="profile_name column-profile_name' . ( in_array( 'profile_name', $hidden, true ) ? ' hidden' : '' ) . '">' . ( empty( $result['profile_name'] ) ? __( 'N/A', 'wp-to-buffer' ) : $result['profile_name'] ) . '</td>
1096 <td class="status_text column-status_text' . ( in_array( 'status_text', $hidden, true ) ? ' hidden' : '' ) . '">' . ( empty( $result['status_text'] ) ? __( 'N/A', 'wp-to-buffer' ) : nl2br( $result['status_text'] ) ) . '</td>
1097 <td class="result column-result' . ( in_array( 'result', $hidden, true ) ? ' hidden' : '' ) . '">' . ucfirst( $result['result'] ) . '</td>';
1098
1099 switch ( $result['result'] ) {
1100 case 'success':
1101 $html .= ' <td class="result_message column-result_message' . ( in_array( 'result_message', $hidden, true ) ? ' hidden' : '' ) . '">' . $result['result_message'] . '</td>
1102 <td class="status_created_at column-status_created_at' . ( in_array( 'status_created_at', $hidden, true ) ? ' hidden' : '' ) . '">' . get_date_from_gmt( $result['status_created_at'], get_option( 'date_format' ) . ' H:i:s' ) . '</td>
1103 <td class="status_due_at column-status_due_at' . ( in_array( 'status_due_at', $hidden, true ) ? ' hidden' : '' ) . '">' . ( ( $result['status_due_at'] !== '0000-00-00 00:00:00' ) ? get_date_from_gmt( $result['status_due_at'], get_option( 'date_format' ) . ' H:i:s' ) : '' ) . '</td>';
1104 break;
1105
1106 case 'test':
1107 $html .= ' <td class="result_message column-result_message' . ( in_array( 'result_message', $hidden, true ) ? ' hidden' : '' ) . '">' . $result['result_message'] . '</td>
1108 <td class="status_created_at column-status_created_at' . ( in_array( 'status_created_at', $hidden, true ) ? ' hidden' : '' ) . '">' . get_date_from_gmt( $result['status_created_at'], get_option( 'date_format' ) . ' H:i:s' ) . '</td>
1109 <td class="status_due_at column-status_due_at' . ( in_array( 'status_due_at', $hidden, true ) ? ' hidden' : '' ) . '">' . ( ( $result['status_due_at'] !== '0000-00-00 00:00:00' ) ? get_date_from_gmt( $result['status_due_at'], get_option( 'date_format' ) . ' H:i:s' ) : '' ) . '</td>';
1110 break;
1111
1112 default:
1113 $html .= ' <td class="result_message column-result_message' . ( in_array( 'result_message', $hidden, true ) ? ' hidden' : '' ) . '">' . nl2br( $result['result_message'] ) . '</td>
1114 <td class="status_created_at column-status_created_at' . ( in_array( 'status_created_at', $hidden, true ) ? ' hidden' : '' ) . '">&nbsp;</td>
1115 <td class="status_due_at column-status_due_at' . ( in_array( 'status_due_at', $hidden, true ) ? ' hidden' : '' ) . '">&nbsp;</td>';
1116 break;
1117 }
1118
1119 $html .= '</tr>';
1120 }
1121
1122 // Return.
1123 return $html;
1124
1125 }
1126
1127 }
1128