PluginProbe
Social Media Auto Poster – Schedule & Publish to Buffer / trunk
Social Media Auto Poster – Schedule & Publish to Buffer vtrunk
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 3.8.8 All 124 releases
wp-to-buffer / lib / social / includes / class-log.php

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

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