forked from LiveCarta/LiveCartaWP
Changed source root directory
This commit is contained in:
@@ -0,0 +1,489 @@
|
||||
<?php
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
require_once dirname(__DIR__) . '/PostmanLogFields.php';
|
||||
require_once 'PostmanEmailLogService.php';
|
||||
require_once 'PostmanEmailLogView.php';
|
||||
require_once 'PostmanEmailLogMigration.php';
|
||||
|
||||
/**
|
||||
*
|
||||
* @author jasonhendriks
|
||||
*/
|
||||
class PostmanEmailLogController {
|
||||
const RESEND_MAIL_AJAX_SLUG = 'postman_resend_mail';
|
||||
private $rootPluginFilenameAndPath;
|
||||
private $logger;
|
||||
|
||||
/**
|
||||
*/
|
||||
function __construct( $rootPluginFilenameAndPath ) {
|
||||
$this->rootPluginFilenameAndPath = $rootPluginFilenameAndPath;
|
||||
$this->logger = new PostmanLogger( get_class( $this ) );
|
||||
if ( PostmanOptions::getInstance()->isMailLoggingEnabled() ) {
|
||||
add_action( 'admin_menu', array(
|
||||
$this,
|
||||
'postmanAddMenuItem',
|
||||
),20 );
|
||||
} else {
|
||||
$this->logger->trace( 'not creating PostmanEmailLog admin menu item' );
|
||||
}
|
||||
if ( PostmanUtils::isCurrentPagePostmanAdmin( 'postman_email_log' ) ) {
|
||||
$this->logger->trace( 'on postman email log page' );
|
||||
|
||||
add_action( 'admin_post_delete', array(
|
||||
$this,
|
||||
'delete_log_item',
|
||||
) );
|
||||
add_action( 'admin_post_view', array(
|
||||
$this,
|
||||
'view_log_item',
|
||||
) );
|
||||
add_action( 'admin_post_transcript', array(
|
||||
$this,
|
||||
'view_transcript_log_item',
|
||||
) );
|
||||
add_action( 'admin_init', array(
|
||||
$this,
|
||||
'on_admin_init',
|
||||
) );
|
||||
}
|
||||
|
||||
$email_logs = new PostmanEmailLogs;
|
||||
|
||||
add_action( 'wp_ajax_post_smtp_log_trash_all', array( $this, 'post_smtp_log_trash_all' ) );
|
||||
|
||||
add_action( 'wp_ajax_ps-get-email-logs', array( $email_logs, 'get_logs_ajax' ) );
|
||||
|
||||
add_action( 'wp_ajax_ps-delete-email-logs', array( $email_logs, 'delete_logs_ajax' ) );
|
||||
|
||||
add_action( 'wp_ajax_ps-export-email-logs', array( $email_logs, 'export_log_ajax' ) );
|
||||
|
||||
add_action( 'wp_ajax_ps-view-log', array( $email_logs, 'view_log_ajax' ) );
|
||||
|
||||
add_action( 'wp_ajax_ps-resend-email', array( $email_logs, 'resend_email' ) );
|
||||
|
||||
if ( is_admin() ) {
|
||||
$actionName = self::RESEND_MAIL_AJAX_SLUG;
|
||||
$fullname = 'wp_ajax_' . $actionName;
|
||||
|
||||
add_action( $fullname, array(
|
||||
$this,
|
||||
'resendMail',
|
||||
) );
|
||||
}
|
||||
}
|
||||
|
||||
function post_smtp_log_trash_all() {
|
||||
check_admin_referer('post-smtp', 'security' );
|
||||
|
||||
if ( ! current_user_can( Postman::MANAGE_POSTMAN_CAPABILITY_LOGS ) ) {
|
||||
wp_send_json_error( 'No permissions to manage Post SMTP logs.');
|
||||
}
|
||||
|
||||
$purger = new PostmanEmailLogPurger();
|
||||
$purger->removeAll();
|
||||
wp_send_json_success();
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
function on_admin_init() {
|
||||
$this->handleBulkAction();
|
||||
// register the stylesheet and javascript external resources
|
||||
$pluginData = apply_filters( 'postman_get_plugin_metadata', null );
|
||||
|
||||
wp_register_script( 'postman-datatable', plugins_url( 'assets/js/dataTable.min.js', $this->rootPluginFilenameAndPath ), array(), $pluginData ['version'] );
|
||||
|
||||
wp_register_style( 'postman-datatable', plugins_url( 'assets/css/dataTable.min.css', $this->rootPluginFilenameAndPath ), array(), $pluginData ['version'] );
|
||||
|
||||
wp_register_script( 'postman-email-logs-script', plugins_url( 'script/postman-email-logs.js', $this->rootPluginFilenameAndPath ), array(
|
||||
PostmanViewController::JQUERY_SCRIPT,
|
||||
PostmanViewController::POSTMAN_SCRIPT,
|
||||
'postman-datatable'
|
||||
), $pluginData ['version'] );
|
||||
|
||||
$localize = array(
|
||||
'DTCols' => array(
|
||||
array( 'data' => 'id' ),
|
||||
array( 'data' => 'original_subject' ),
|
||||
array( 'data' => 'original_to' ),
|
||||
array( 'data' => 'time' ),
|
||||
array( 'data' => 'success' ),
|
||||
array( 'data' => 'actions' )
|
||||
)
|
||||
);
|
||||
|
||||
/**
|
||||
* Filters JS localize
|
||||
*
|
||||
* @param array $localize
|
||||
* @since 2.5.0
|
||||
* @version 1.0.0
|
||||
*/
|
||||
$localize = apply_filters( 'post_smtp_email_logs_localize', $localize );
|
||||
|
||||
wp_localize_script(
|
||||
'postman-email-logs-script',
|
||||
'PSEmailLogs',
|
||||
$localize
|
||||
);
|
||||
|
||||
$this->handleCsvExport();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles CSV Export
|
||||
*
|
||||
* @since 2.1.1 used implode, to prevent email logs from being broken
|
||||
* @version 1.0.1
|
||||
*/
|
||||
function handleCsvExport() {
|
||||
if ( ! isset( $_GET['postman_export_csv'] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! isset( $_REQUEST['post-smtp-log-nonce'] ) || ! wp_verify_nonce( $_REQUEST['post-smtp-log-nonce'], 'post-smtp' ) ) {
|
||||
wp_die( 'Security check' );
|
||||
}
|
||||
|
||||
if ( current_user_can( Postman::MANAGE_POSTMAN_CAPABILITY_LOGS ) ) {
|
||||
$args = array(
|
||||
'post_type' => PostmanEmailLogPostType::POSTMAN_CUSTOM_POST_TYPE_SLUG,
|
||||
'post_status' => PostmanEmailLogService::POSTMAN_CUSTOM_POST_STATUS_PRIVATE,
|
||||
'posts_per_page' => -1,
|
||||
);
|
||||
$logs = new WP_Query($args);
|
||||
|
||||
if ( empty( $logs->posts ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
header('Content-Type: text/csv');
|
||||
header('Content-Disposition: attachment; filename="email-logs.csv"');
|
||||
|
||||
$fp = fopen('php://output', 'wb');
|
||||
|
||||
$headers = array_keys( PostmanLogFields::get_instance()->get_fields() );
|
||||
$headers[] = 'delivery_time';
|
||||
|
||||
fputcsv($fp, $headers);
|
||||
|
||||
$date_format = get_option( 'date_format' );
|
||||
$time_format = get_option( 'time_format' );
|
||||
|
||||
foreach ( $logs->posts as $log ) {
|
||||
$meta = PostmanLogFields::get_instance()->get($log->ID);
|
||||
$data = [];
|
||||
foreach ( $meta as $header => $line ) {
|
||||
$data[] = is_array( $line[0] ) ? implode( PostmanMessage::EOL, $line[0] ) : $line[0];
|
||||
}
|
||||
$data[] = date( "$date_format $time_format", strtotime( $log->post_date ) );
|
||||
fputcsv($fp, $data);
|
||||
}
|
||||
|
||||
fclose($fp);
|
||||
die();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
public function resendMail() {
|
||||
check_admin_referer( 'resend', 'security' );
|
||||
|
||||
// get the email address of the recipient from the HTTP Request
|
||||
$postid = $this->getRequestParameter( 'email' );
|
||||
if ( ! empty( $postid ) ) {
|
||||
$meta_values = PostmanLogFields::get_instance()->get( $postid );
|
||||
|
||||
if ( isset( $_POST['mail_to'] ) && ! empty( $_POST['mail_to'] ) ) {
|
||||
$emails = explode( ',', $_POST['mail_to'] );
|
||||
$to = array_map( 'sanitize_email', $emails );
|
||||
} else {
|
||||
$to = $meta_values ['original_to'] [0];
|
||||
}
|
||||
|
||||
$success = wp_mail( $to, $meta_values ['original_subject'] [0], $meta_values ['original_message'] [0], $meta_values ['original_headers'] [0] );
|
||||
|
||||
// Postman API: retrieve the result of sending this message from Postman
|
||||
$result = apply_filters( 'postman_wp_mail_result', null );
|
||||
$transcript = $result ['transcript'];
|
||||
|
||||
// post-handling
|
||||
if ( $success ) {
|
||||
$this->logger->debug( 'Email was successfully re-sent' );
|
||||
// the message was sent successfully, generate an appropriate message for the user
|
||||
$statusMessage = sprintf( __( 'Your message was delivered (%d ms) to the SMTP server! Congratulations :)', 'post-smtp' ), $result ['time'] );
|
||||
|
||||
// compose the JSON response for the caller
|
||||
$response = array(
|
||||
'message' => $statusMessage,
|
||||
'transcript' => $transcript,
|
||||
);
|
||||
$this->logger->trace( 'AJAX response' );
|
||||
$this->logger->trace( $response );
|
||||
// send the JSON response
|
||||
wp_send_json_success( $response );
|
||||
} else {
|
||||
$this->logger->error( 'Email was not successfully re-sent - ' . $result ['exception']->getCode() );
|
||||
// the message was NOT sent successfully, generate an appropriate message for the user
|
||||
$statusMessage = $result ['exception']->getMessage();
|
||||
|
||||
// compose the JSON response for the caller
|
||||
$response = array(
|
||||
'message' => $statusMessage,
|
||||
'transcript' => $transcript,
|
||||
);
|
||||
$this->logger->trace( 'AJAX response' );
|
||||
$this->logger->trace( $response );
|
||||
// send the JSON response
|
||||
wp_send_json_error( $response );
|
||||
}
|
||||
} else {
|
||||
// compose the JSON response for the caller
|
||||
$response = array();
|
||||
// send the JSON response
|
||||
wp_send_json_error( $response );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO move this somewhere reusable
|
||||
*
|
||||
* @param mixed $parameterName
|
||||
* @return mixed
|
||||
*/
|
||||
private function getRequestParameter( $parameterName ) {
|
||||
if ( isset( $_POST [ $parameterName ] ) ) {
|
||||
$value = sanitize_text_field( $_POST [ $parameterName ] );
|
||||
$this->logger->trace( sprintf( 'Found parameter "%s"', $parameterName ) );
|
||||
$this->logger->trace( $value );
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* From https://www.skyverge.com/blog/add-custom-bulk-action/
|
||||
*/
|
||||
function handleBulkAction() {
|
||||
// only do this for administrators
|
||||
if ( PostmanUtils::isAdmin() && isset( $_REQUEST ['email_log_entry'] ) ) {
|
||||
$this->logger->trace( 'handling bulk action' );
|
||||
if ( wp_verify_nonce( $_REQUEST ['_wpnonce'], 'bulk-email_log_entries' ) ) {
|
||||
$this->logger->trace( sprintf( 'nonce "%s" passed validation', sanitize_text_field($_REQUEST ['_wpnonce']) ) );
|
||||
if ( isset( $_REQUEST ['action'] ) && ($_REQUEST ['action'] == 'bulk_delete' || $_REQUEST ['action2'] == 'bulk_delete') ) {
|
||||
$this->logger->trace( sprintf( 'handling bulk delete' ) );
|
||||
$purger = new PostmanEmailLogPurger();
|
||||
$postids = array_map( 'absint', $_REQUEST ['email_log_entry'] );
|
||||
foreach ( $postids as $postid ) {
|
||||
$purger->verifyLogItemExistsAndRemove( $postid );
|
||||
}
|
||||
$mh = new PostmanMessageHandler();
|
||||
$mh->addMessage( __( 'Mail Log Entries were deleted.', 'post-smtp' ) );
|
||||
} else {
|
||||
$this->logger->warn( sprintf( 'action "%s" not recognized', sanitize_text_field($_REQUEST ['action']) ) );
|
||||
}
|
||||
} else {
|
||||
$this->logger->warn( sprintf( 'nonce "%s" failed validation', sanitize_text_field($_REQUEST ['_wpnonce']) ) );
|
||||
}
|
||||
$this->redirectToLogPage();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
function delete_log_item() {
|
||||
// only do this for administrators
|
||||
if ( PostmanUtils::isAdmin() ) {
|
||||
$this->logger->trace( 'handling delete item' );
|
||||
$postid = absint($_REQUEST ['email']);
|
||||
if ( wp_verify_nonce( $_REQUEST ['_wpnonce'], 'delete_email_log_item_' . $postid ) ) {
|
||||
$this->logger->trace( sprintf( 'nonce "%s" passed validation', sanitize_text_field($_REQUEST ['_wpnonce']) ) );
|
||||
$purger = new PostmanEmailLogPurger();
|
||||
$purger->verifyLogItemExistsAndRemove( $postid );
|
||||
$mh = new PostmanMessageHandler();
|
||||
$mh->addMessage( __( 'Mail Log Entry was deleted.', 'post-smtp' ) );
|
||||
} else {
|
||||
$this->logger->warn( sprintf( 'nonce "%s" failed validation', sanitize_text_field($_REQUEST ['_wpnonce']) ) );
|
||||
}
|
||||
$this->redirectToLogPage();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
function view_log_item() {
|
||||
// Check if user has permission to view email logs
|
||||
if ( ! current_user_can( Postman::MANAGE_POSTMAN_CAPABILITY_LOGS ) ) {
|
||||
wp_die( __( 'Sorry, you are not allowed to view email logs.', 'post-smtp' ) );
|
||||
}
|
||||
|
||||
$this->logger->trace( 'handling view item' );
|
||||
$postid = absint( $_REQUEST ['email'] );
|
||||
$post = get_post( $postid );
|
||||
|
||||
if ( $post->post_type !== 'postman_sent_mail' ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$meta_values = PostmanLogFields::get_instance()->get( $postid );
|
||||
// https://css-tricks.com/examples/hrs/
|
||||
print '<html><head><style>body {font-family: monospace;} hr {
|
||||
border: 0;
|
||||
border-bottom: 1px dashed #ccc;
|
||||
background: #bbb;
|
||||
}</style></head><body>';
|
||||
print '<table>';
|
||||
if ( ! empty( $meta_values ['from_header'] [0] ) ) {
|
||||
printf( '<tr><th style="text-align:right">%s:</th><td>%s</td></tr>', _x( 'From', 'Who is this message From?', 'post-smtp' ), esc_html( $meta_values ['from_header'] [0] ) );
|
||||
}
|
||||
// show the To header (it's optional)
|
||||
if ( ! empty( $meta_values ['to_header'] [0] ) ) {
|
||||
printf( '<tr><th style="text-align:right">%s:</th><td>%s</td></tr>', _x( 'To', 'Who is this message To?', 'post-smtp' ), esc_html( $meta_values ['to_header'] [0] ) );
|
||||
}
|
||||
// show the Cc header (it's optional)
|
||||
if ( ! empty( $meta_values ['cc_header'] [0] ) ) {
|
||||
printf( '<tr><th style="text-align:right">%s:</th><td>%s</td></tr>', _x( 'Cc', 'Who is this message Cc\'d to?', 'post-smtp' ), esc_html( $meta_values ['cc_header'] [0] ) );
|
||||
}
|
||||
// show the Bcc header (it's optional)
|
||||
if ( ! empty( $meta_values ['bcc_header'] [0] ) ) {
|
||||
printf( '<tr><th style="text-align:right">%s:</th><td>%s</td></tr>', _x( 'Bcc', 'Who is this message Bcc\'d to?', 'post-smtp' ), esc_html( $meta_values ['bcc_header'] [0] ) );
|
||||
}
|
||||
// show the Reply-To header (it's optional)
|
||||
if ( ! empty( $meta_values ['reply_to_header'] [0] ) ) {
|
||||
printf( '<tr><th style="text-align:right">%s:</th><td>%s</td></tr>', __( 'Reply-To', 'post-smtp' ), esc_html( $meta_values ['reply_to_header'] [0] ) );
|
||||
}
|
||||
printf( '<tr><th style="text-align:right">%s:</th><td>%s</td></tr>', _x( 'Date', 'What is the date today?', 'post-smtp' ), $post->post_date );
|
||||
printf( '<tr><th style="text-align:right">%s:</th><td>%s</td></tr>', _x( 'Subject', 'What is the subject of this message?', 'post-smtp' ), esc_html( $post->post_title ) );
|
||||
// The Transport UI is always there, in more recent versions that is
|
||||
if ( ! empty( $meta_values ['transport_uri'] [0] ) ) {
|
||||
printf( '<tr><th style="text-align:right">%s:</th><td>%s</td></tr>', _x( 'Delivery-URI', 'What is the unique URI of the configuration?', 'post-smtp' ), esc_html( $meta_values ['transport_uri'] [0] ) );
|
||||
}
|
||||
print '</table>';
|
||||
print '<hr/>';
|
||||
print '<pre>';
|
||||
print $this->sanitize_message( $post->post_content );
|
||||
print '</pre>';
|
||||
print '</body></html>';
|
||||
die();
|
||||
}
|
||||
|
||||
function sanitize_message( $message ) {
|
||||
$allowed_tags = wp_kses_allowed_html( 'post' );
|
||||
$allowed_tags['style'] = array();
|
||||
|
||||
return wp_kses( $message, $allowed_tags );
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
function view_transcript_log_item() {
|
||||
// Check if user has permission to view email logs
|
||||
if ( ! current_user_can( Postman::MANAGE_POSTMAN_CAPABILITY_LOGS ) ) {
|
||||
wp_die( __( 'Sorry, you are not allowed to view email logs.', 'post-smtp' ) );
|
||||
}
|
||||
|
||||
$this->logger->trace( 'handling view transcript item' );
|
||||
$postid = absint($_REQUEST ['email']);
|
||||
$post = get_post( $postid );
|
||||
$meta_values = PostmanLogFields::get_instance()->get( $postid );
|
||||
// https://css-tricks.com/examples/hrs/
|
||||
print '<html><head><style>body {font-family: monospace;} hr {
|
||||
border: 0;
|
||||
border-bottom: 1px dashed #ccc;
|
||||
background: #bbb;
|
||||
}</style></head><body>';
|
||||
printf( '<p>%s</p>', __( 'This is the conversation between Postman and the mail server. It can be useful for diagnosing problems. <b>DO NOT</b> post it on-line, it may contain your account password.', 'post-smtp' ) );
|
||||
print '<hr/>';
|
||||
print '<pre>';
|
||||
if ( ! empty( $meta_values ['session_transcript'] [0] ) ) {
|
||||
print esc_html( $meta_values ['session_transcript'] [0] );
|
||||
} else {
|
||||
/* Translators: Meaning "Not Applicable" */
|
||||
print __( 'n/a', 'post-smtp' );
|
||||
}
|
||||
print '</pre>';
|
||||
print '</body></html>';
|
||||
die();
|
||||
}
|
||||
|
||||
/**
|
||||
* For whatever reason, PostmanUtils::get..url doesn't work here? :(
|
||||
*/
|
||||
function redirectToLogPage() {
|
||||
PostmanUtils::redirect( PostmanUtils::POSTMAN_EMAIL_LOG_PAGE_RELATIVE_URL );
|
||||
die();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the page
|
||||
*/
|
||||
function postmanAddMenuItem() {
|
||||
// only do this for administrators
|
||||
if ( PostmanUtils::isAdmin() ) {
|
||||
$this->logger->trace( 'created PostmanEmailLog admin menu item' );
|
||||
/*
|
||||
Translators where (%s) is the name of the plugin */
|
||||
$pageTitle = sprintf( __( '%s Email Log', 'post-smtp' ), __( 'Post SMTP', 'post-smtp' ) );
|
||||
$pluginName = _x( 'Email Log', 'The log of Emails that have been delivered', 'post-smtp' );
|
||||
|
||||
$page = add_submenu_page( PostmanViewController::POSTMAN_MENU_SLUG, $pageTitle, $pluginName, Postman::MANAGE_POSTMAN_CAPABILITY_LOGS, 'postman_email_log', array( $this, 'postman_render_email_page' ) );
|
||||
|
||||
// When the plugin options page is loaded, also load the stylesheet
|
||||
add_action( 'admin_print_styles-' . $page, array(
|
||||
$this,
|
||||
'postman_email_log_enqueue_resources',
|
||||
) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueus Styles/ Scripts
|
||||
*
|
||||
* @since 2.1 Changed stylesheet
|
||||
* @version 1.0
|
||||
*/
|
||||
function postman_email_log_enqueue_resources() {
|
||||
|
||||
wp_enqueue_style( PostmanViewController::POSTMAN_STYLE );
|
||||
wp_enqueue_script( 'postman-datatable' );
|
||||
wp_enqueue_style( 'postman-datatable' );
|
||||
wp_enqueue_script( 'postman-email-logs-script' );
|
||||
wp_enqueue_script( 'sprintf' );
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* *************************** RENDER TEST PAGE ********************************
|
||||
* ******************************************************************************
|
||||
* This function renders the admin page and the example list table.
|
||||
* Although it's
|
||||
* possible to call prepare_items() and display() from the constructor, there
|
||||
* are often times where you may need to include logic here between those steps,
|
||||
* so we've instead called those methods explicitly. It keeps things flexible, and
|
||||
* it's the way the list tables are used in the WordPress core.
|
||||
*/
|
||||
function postman_render_email_page() {
|
||||
|
||||
$new_logging = get_option( 'postman_db_version' );
|
||||
|
||||
//Logging with new system
|
||||
if( $new_logging ) {
|
||||
|
||||
require 'PostmanEmailLogTable.php';
|
||||
|
||||
}
|
||||
//Still logging with old system
|
||||
else {
|
||||
|
||||
require 'PostmanEmailLogLegacy.php';
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
<?php
|
||||
// Create an instance of our package class...
|
||||
$testListTable = new PostmanEmailLogView();
|
||||
wp_enqueue_script( 'postman-email-logs-script' );
|
||||
// Fetch, prepare, sort, and filter our data...
|
||||
$testListTable->prepare_items();
|
||||
?>
|
||||
<div class="wrap">
|
||||
|
||||
<div id="icon-users" class="icon32">
|
||||
<br />
|
||||
</div>
|
||||
<h2><?php
|
||||
/* Translators where (%s) is the name of the plugin */
|
||||
echo sprintf( __( '%s Email Log', 'post-smtp' ), __( 'Post SMTP', 'post-smtp' ) )?></h2>
|
||||
|
||||
<?php //include_once POST_SMTP_PATH . '/Postman/extra/donation.php'; ?>
|
||||
|
||||
<div class="ps-config-bar">
|
||||
<p><?php
|
||||
|
||||
echo __( 'This is a record of deliveries made to the mail server. It does not neccessarily indicate sucessful delivery to the recipient.', 'post-smtp' )?></p>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
$from_date = isset( $_GET['from_date'] ) ? sanitize_text_field( $_GET['from_date'] ) : '';
|
||||
$to_date = isset( $_GET['to_date'] ) ? sanitize_text_field( $_GET['to_date'] ) : '';
|
||||
$search = isset( $_GET['search'] ) ? sanitize_text_field( $_GET['search'] ) : '';
|
||||
$page_records = apply_filters( 'postman_log_per_page', array( 10, 15, 25, 50, 75, 100 ) );
|
||||
$postman_page_records = isset( $_GET['postman_page_records'] ) ? absint( $_GET['postman_page_records'] ) : '';
|
||||
?>
|
||||
|
||||
<form id="postman-email-log-filter" action="<?php echo admin_url( PostmanUtils::POSTMAN_EMAIL_LOG_PAGE_RELATIVE_URL ); ?>" method="get">
|
||||
<input type="hidden" name="page" value="postman_email_log">
|
||||
<input type="hidden" name="post-smtp-filter" value="1">
|
||||
<?php wp_nonce_field('post-smtp', 'post-smtp-log-nonce'); ?>
|
||||
|
||||
<div id="email-log-filter" class="postman-log-row">
|
||||
<div class="form-control">
|
||||
<label for="from_date"><?php _e( 'From Date', 'post-smtp' ); ?></label>
|
||||
<input id="from_date" class="email-log-date" value="<?php echo esc_attr($from_date); ?>" type="text" name="from_date" placeholder="<?php _e( 'From Date', 'post-smtp' ); ?>">
|
||||
</div>
|
||||
<div class="form-control">
|
||||
<label for="to_date"><?php _e( 'To Date', 'post-smtp' ); ?></label>
|
||||
<input id="to_date" class="email-log-date" value="<?php echo esc_attr($to_date); ?>" type="text" name="to_date" placeholder="<?php _e( 'To Date', 'post-smtp' ); ?>">
|
||||
</div>
|
||||
<div class="form-control">
|
||||
<label for="search"><?php _e( 'Search', 'post-smtp' ); ?></label>
|
||||
<input id="search" type="text" name="search" value="<?php echo esc_attr($search); ?>" placeholder="<?php _e( 'Search', 'post-smtp' ); ?>">
|
||||
</div>
|
||||
<div class="form-control">
|
||||
<label id="postman_page_records"><?php _e( 'Records per page', 'post-smtp' ); ?></label>
|
||||
<select id="postman_page_records" name="postman_page_records">
|
||||
<?php
|
||||
foreach ( $page_records as $value ) {
|
||||
$selected = selected( $postman_page_records, $value, false );
|
||||
echo '<option value="' . $value . '"' . $selected . '>' . $value . '</option>';
|
||||
}
|
||||
?>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-control" style="padding: 0 5px 0 5px;">
|
||||
<button type="submit" name="filter" class="ps-btn-orange"><?php _e( 'Filter/Search', 'post-smtp' ); ?></button>
|
||||
</div>
|
||||
|
||||
<div class="form-control" style="padding: 0 5px 0 0px;">
|
||||
<button type="submit" id="postman_export_csv" name="postman_export_csv" class="ps-btn-orange"><?php _e( 'Export To CSV', 'post-smtp' ); ?></button>
|
||||
</div>
|
||||
|
||||
<div class="form-control">
|
||||
<button type="submit" id="postman_trash_all" name="postman_trash_all" class="ps-btn-red"><?php _e( 'Trash All', 'post-smtp' ); ?></button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="error">Please notice: when you select a date for example 11/20/2017, behind the scene the query select <b>11/20/2017 00:00:00</b>.<br>So if you searching for an email arrived that day at any hour you need to select 11/20/2017 as the <b>From Date</b> and 11/21/2017 as the <b>To Date</b>.</div>
|
||||
</form>
|
||||
|
||||
<!-- Forms are NOT created automatically, so you need to wrap the table in one to use features like bulk actions -->
|
||||
<form id="movies-filter" method="get">
|
||||
<!-- For plugins, we also need to ensure that the form posts back to our current page -->
|
||||
<input type="hidden" name="page"
|
||||
value="<?php echo esc_attr( filter_input( INPUT_GET, 'page', FILTER_SANITIZE_FULL_SPECIAL_CHARS ) ?: '' ); ?>" />
|
||||
|
||||
<!-- Now we can render the completed list table -->
|
||||
<?php $testListTable->display()?>
|
||||
</form>
|
||||
|
||||
<?php add_thickbox(); ?>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,910 @@
|
||||
<?php
|
||||
|
||||
if( !class_exists( 'PostmanEmailLogsMigration' ) ):
|
||||
class PostmanEmailLogsMigration {
|
||||
|
||||
private $new_logging = false;
|
||||
private $migrating = false;
|
||||
private $have_old_logs = false;
|
||||
private $logging_file = '';
|
||||
private $logging_file_url = '';
|
||||
|
||||
/**
|
||||
* Constructor PostmanEmailLogsMigration
|
||||
*
|
||||
* @since 2.4.0
|
||||
* @version 1.0.0
|
||||
*/
|
||||
public function __construct() {
|
||||
|
||||
if( is_multisite() ) {
|
||||
|
||||
$this->logging_file = WP_CONTENT_DIR . '/post-smtp-migration-' . get_current_blog_id() . '.log';
|
||||
$this->logging_file_url = WP_CONTENT_URL . '/post-smtp-migration-' . get_current_blog_id() . '.log';
|
||||
|
||||
}
|
||||
else {
|
||||
|
||||
$this->logging_file = WP_CONTENT_DIR . '/post-smtp-migration.log';
|
||||
$this->logging_file_url = WP_CONTENT_URL . '/post-smtp-migration.log';
|
||||
|
||||
}
|
||||
|
||||
$this->new_logging = get_option( 'postman_db_version' );
|
||||
$this->migrating = get_option( 'ps_migrate_logs' );
|
||||
$this->have_old_logs = $this->have_old_logs();
|
||||
$hide_notice = get_transient( 'ps_dismiss_update_notice' );
|
||||
|
||||
//Show DB Update Notice
|
||||
if(
|
||||
( !$hide_notice )
|
||||
&&
|
||||
( $this->have_old_logs && !$this->has_migrated() )
|
||||
||
|
||||
( $this->has_migrated() && $this->have_old_logs && isset( $_GET['page'] ) && $_GET['page'] == 'postman_email_log' )
|
||||
) {
|
||||
|
||||
add_action( 'admin_notices', array( $this, 'notice' ) );
|
||||
|
||||
}
|
||||
|
||||
if( isset( $_GET['action'] ) && $_GET['action'] == 'ps-migrate-logs' ) {
|
||||
|
||||
$this->update_database();
|
||||
|
||||
}
|
||||
|
||||
if( isset( $_GET['action'] ) && $_GET['action'] == 'ps-delete-old-logs' ) {
|
||||
|
||||
$this->log( 'Info: Delete old logs' );
|
||||
|
||||
$this->trash_all_old_logs();
|
||||
|
||||
}
|
||||
|
||||
//Add Hook of Migration, Schedule Migration
|
||||
if( $this->migrating && ( isset( $_GET['page'] ) && $_GET['page'] == 'postman_email_log' ) ) {
|
||||
|
||||
add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_script' ) );
|
||||
|
||||
}
|
||||
|
||||
//Switch back to old system
|
||||
if( isset( $_GET['action'] ) && $_GET['action'] == 'ps-switch-back' ) {
|
||||
|
||||
$this->switch_back();
|
||||
|
||||
}
|
||||
|
||||
//Switch to new system
|
||||
if( isset( $_GET['action'] ) && $_GET['action'] == 'ps-switch-to-new' ) {
|
||||
|
||||
$this->switch_to_new();
|
||||
|
||||
}
|
||||
|
||||
//Revert Migration
|
||||
if( isset( $_GET['action'] ) && $_GET['action'] == 'ps-revert-migration' ) {
|
||||
|
||||
$this->revert_migration();
|
||||
|
||||
}
|
||||
|
||||
//Skip Migration
|
||||
if( isset( $_GET['action'] ) && $_GET['action'] == 'ps-skip-migration' ) {
|
||||
|
||||
$this->skip_migration();
|
||||
|
||||
}
|
||||
|
||||
add_action( 'wp_ajax_ps-migrate-logs', array( $this, 'migrate_logs' ) );
|
||||
add_action( 'wp_ajax_ps-db-update-notice-dismiss', array( $this, 'dismiss_update_notice' ) );
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Checks if have logs in old system
|
||||
*
|
||||
* @since 2.5.0
|
||||
* @version 1.0.0
|
||||
*/
|
||||
public function have_old_logs() {
|
||||
|
||||
global $wpdb;
|
||||
|
||||
$data = $wpdb->get_results(
|
||||
"SELECT ID FROM {$wpdb->posts} WHERE post_type = 'postman_sent_mail' LIMIT 1;"
|
||||
);
|
||||
|
||||
if( !empty( $data ) ) {
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Shows DB Update Notice | Action call-back
|
||||
*
|
||||
* @since 2.4.0
|
||||
* @version 1.0.0
|
||||
*/
|
||||
public function notice() {
|
||||
|
||||
$security = wp_create_nonce( 'ps-migrate-logs' );
|
||||
$migration_url = admin_url( 'admin.php?page=postman' ) . '&security=' . $security . '&action=ps-migrate-logs';
|
||||
$delete_url = admin_url( 'admin.php?page=postman_email_log' ) . '&security=' . $security . '&action=ps-delete-old-logs';
|
||||
$switch_back = admin_url( 'admin.php?page=postman_email_log' ) . '&security=' . $security . '&action=ps-switch-back';
|
||||
$switch_to_new = admin_url( 'admin.php?page=postman_email_log' ) . '&security=' . $security . '&action=ps-switch-to-new';
|
||||
$status_url = admin_url( 'admin.php?page=postman_email_log' );
|
||||
$total_old_logs = wp_count_posts( 'postman_sent_mail' );
|
||||
$this->migrating = get_option( 'ps_migrate_logs' );
|
||||
$migrated_logs = $this->get_migrated_count();
|
||||
$current_page = isset( $_GET['page'] ) ? $_GET['page'] : '';
|
||||
$new_logging = get_option( 'postman_db_version' );
|
||||
$dismissible = ( $this->have_old_logs() && !$this->has_migrated() && !$this->migrating ) ? 'is-dismissible' : '';
|
||||
$revert_url = admin_url( 'admin.php?page=postman_email_log' ) . '&security=' . $security . '&action=ps-revert-migration';
|
||||
$skip_migration_url = admin_url( 'admin.php?page=postman_email_log' ) . '&security=' . $security . '&action=ps-skip-migration';
|
||||
|
||||
?>
|
||||
<div class="notice ps-db-update-notice <?php echo esc_attr( $dismissible ); ?>" style="border: 1px solid #2271b1; border-left-width: 4px;">
|
||||
<input type="hidden" value="<?php echo esc_attr( $security ); ?>" class="ps-security">
|
||||
<p><b><?php _e( 'Post SMTP database update required', 'post-smtp' ); ?></b></p>
|
||||
<?php if( $this->have_old_logs && !$this->migrating && !$this->is_migrated() ): ?>
|
||||
<p><?php echo _e( 'Post SMTP has been updated! To keep things running smoothly, we have to update your database to the newest version, migrate email logs to new system. The database update process runs in the background and may take a little while, so please be patient.', 'post-smtp' ); ?></p>
|
||||
<a href="<?php echo esc_url( $migration_url ) ?>" class="button button-primary">Update and Migrate Logs</a>
|
||||
<?php endif; ?>
|
||||
<?php if(
|
||||
( $this->is_migrated() && $current_page !== 'postman_email_log' )
|
||||
||
|
||||
( $this->migrating )
|
||||
&&
|
||||
( $current_page !== 'postman_email_log' )
|
||||
): ?>
|
||||
<p><?php echo _e( 'Post SMTP is migrating logs to new system.', 'post-smtp' ); ?></p>
|
||||
<a href="<?php echo esc_url( $status_url ); ?>" class="button button-secondary">View Progress →</a>
|
||||
<?php endif; ?>
|
||||
<?php
|
||||
if(
|
||||
$this->have_old_logs()
|
||||
&&
|
||||
$this->is_migrated()
|
||||
&&
|
||||
( $current_page == 'postman_email_log' )
|
||||
&&
|
||||
$new_logging
|
||||
): ?>
|
||||
<p><?php echo _e( 'Great! You have successfully migrated to new logs.', 'post-smtp' ); ?>
|
||||
<?php echo file_exists( $this->logging_file ) ? '<a href="'.$this->logging_file_url.'" target="_blank">View Migration Log</a>' : ''; ?>
|
||||
</p>
|
||||
<a href="<?php echo esc_url( $switch_back ); ?>" class="button button-primary">View old logs</a>
|
||||
<a href="<?php echo esc_url( $delete_url ); ?>" class="button button-primary">Delete old Logs</a>
|
||||
<?php endif; ?>
|
||||
<?php if(
|
||||
$this->migrating
|
||||
&&
|
||||
( isset( $_GET['page'] ) && $_GET['page'] == 'postman_email_log' )
|
||||
): ?>
|
||||
<p><?php _e( 'Post SMTP is migrating logs to new system.', 'post-smtp' ); ?></p>
|
||||
<?php endif; ?>
|
||||
<?php if(
|
||||
!$new_logging
|
||||
&&
|
||||
$this->is_migrated()
|
||||
&&
|
||||
$this->have_old_logs()
|
||||
&&
|
||||
$current_page == 'postman_email_log'
|
||||
): ?>
|
||||
<a href="<?php echo esc_url( $switch_to_new ); ?>" class="button button-primary">Switch to new System</a>
|
||||
<?php endif; ?>
|
||||
<?php
|
||||
if(
|
||||
$this->have_old_logs()
|
||||
&&
|
||||
$this->migrating
|
||||
&&
|
||||
( $current_page == 'postman_email_log' )
|
||||
&&
|
||||
$new_logging
|
||||
): ?>
|
||||
<a href="<?php echo esc_url( $switch_back ); ?>" class="button button-primary">View old logs</a>
|
||||
<?php endif; ?>
|
||||
<?php if(
|
||||
!$new_logging
|
||||
&&
|
||||
$this->migrating
|
||||
&&
|
||||
$this->have_old_logs()
|
||||
&&
|
||||
$current_page == 'postman_email_log'
|
||||
): ?>
|
||||
<a href="<?php echo esc_url( $switch_to_new ); ?>" class="button button-primary">Switch to new System</a>
|
||||
<?php endif; ?>
|
||||
<a href="https://postmansmtp.com/new-and-better-email-log-post-smtp-feature-update/" target="__blank" class="button button-secondary">Learn about migration</a>
|
||||
<div style="float: right">
|
||||
<?php
|
||||
//Revert Migration
|
||||
if( $this->have_old_logs() && $new_logging ) {
|
||||
|
||||
?>
|
||||
<a href="<?php echo esc_url( $revert_url ); ?>" style="font-size: 13px;">Revert Migration</a>
|
||||
<br>
|
||||
<?php
|
||||
|
||||
}
|
||||
if( $this->have_old_logs() ) {
|
||||
|
||||
?>
|
||||
<a href="<?php echo esc_url( $skip_migration_url ); ?>" style="font-size: 13px;">Switch to new logs without migration</a>
|
||||
<?php
|
||||
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
<div style="clear: both;"></div>
|
||||
<div style="margin: 10px 0;"></div>
|
||||
<?php
|
||||
if(
|
||||
$this->migrating
|
||||
&&
|
||||
( isset( $_GET['page'] ) && $_GET['page'] == 'postman_email_log' )
|
||||
) {
|
||||
?>
|
||||
<div class="ps-migration-box" style="text-align: center; width: 100%; margin: 10px 0;">
|
||||
<progress style="width: 100%;" id="ps-migration-progress" value="<?php echo esc_attr( $migrated_logs ); ?>" max="<?php echo esc_attr( $total_old_logs->private ); ?>"></progress>
|
||||
<h5 id="ps-progress"><?php echo esc_attr( "{$migrated_logs}/ {$total_old_logs->private}" ); ?></h5>
|
||||
</div>
|
||||
<?php
|
||||
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
<?php
|
||||
if(
|
||||
$this->have_old_logs
|
||||
&&
|
||||
$this->migrating
|
||||
&&
|
||||
!$this->is_migrated()
|
||||
&&
|
||||
( isset( $_GET['page'] ) && $_GET['page'] == 'postman_email_log' )
|
||||
) {
|
||||
?>
|
||||
<?php
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Updates Database
|
||||
*
|
||||
* @since 2.5.0
|
||||
* @version 1.0.0
|
||||
*/
|
||||
public function update_database() {
|
||||
|
||||
if( !wp_verify_nonce( $_GET['security'], 'ps-migrate-logs' ) ) {
|
||||
|
||||
$this->log( 'Error: Creating table, Nonce Verification Failed' );
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
$this->log( 'Info: Creating table' );
|
||||
|
||||
//Let's start migration
|
||||
|
||||
$email_logs = new PostmanEmailLogs;
|
||||
$email_logs->install_table();
|
||||
|
||||
$this->log( 'Info: Table created' );
|
||||
|
||||
if( $this->have_old_logs && !$this->migrating ) {
|
||||
|
||||
update_option( 'ps_migrate_logs', 1 );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets last old log, to be migrated
|
||||
*
|
||||
* @since 2.5.0
|
||||
* @version 1.0.0
|
||||
*/
|
||||
public function get_last_old_log() {
|
||||
|
||||
global $wpdb;
|
||||
|
||||
return $wpdb->get_results(
|
||||
"SELECT * FROM {$wpdb->postmeta} WHERE post_id = ( SELECT ID FROM {$wpdb->posts} ORDER BY ID DESC LIMIT 1 )"
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Migrate Logs | AJAX call-back
|
||||
*
|
||||
* @since 2.5.0
|
||||
* @version 1.0.0
|
||||
*/
|
||||
public function migrate_logs() {
|
||||
|
||||
if( wp_verify_nonce( $_POST['security'], 'ps-migrate-logs' ) ) {
|
||||
|
||||
if( isset( $_POST['action'] ) && $_POST['action'] == 'ps-migrate-logs' ) {
|
||||
|
||||
if( $this->have_old_logs ) {
|
||||
|
||||
$this->log( 'Info: `migrate_logs` Have old logs' );
|
||||
|
||||
$old_logs = $this->get_old_logs();
|
||||
|
||||
if( $old_logs && !empty( $old_logs )) {
|
||||
|
||||
//Migrating Logs
|
||||
foreach( $old_logs as $ID => $log ) {
|
||||
|
||||
$this->log( 'Info: `migrate_logs` Remove extra keys if contains: ' . print_r( array_keys( $log ), true ) );
|
||||
|
||||
$log = $this->remove_extra_keys( $log );
|
||||
|
||||
$this->log( 'Info: `migrate_logs` Migrating Log: ' . print_r( array_keys( $log ), true ) );
|
||||
|
||||
$result = PostmanEmailLogs::get_instance()->save( $log );
|
||||
|
||||
if( $result ) {
|
||||
|
||||
$this->log( 'Info: `migrate_logs` Log migrated' );
|
||||
|
||||
$result = wp_update_post(
|
||||
array(
|
||||
'ID' => $ID,
|
||||
'pinged' => 1
|
||||
)
|
||||
);
|
||||
|
||||
}
|
||||
else {
|
||||
|
||||
$this->log( 'Error: `migrate_logs` Log not migrated: ID: ' . $ID . print_r( array_keys( $log ), true ) );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//If all migrated
|
||||
if( $this->get_migrated_count() == wp_count_posts( 'postman_sent_mail' )->private ) {
|
||||
|
||||
$this->log( 'Info: `migrate_logs` All logs migrated' );
|
||||
|
||||
delete_option( 'ps_migrate_logs' );
|
||||
|
||||
wp_send_json_success(
|
||||
array(
|
||||
'migrated' => $this->get_migrated_count(),
|
||||
'total' => wp_count_posts( 'postman_sent_mail' )->private
|
||||
),
|
||||
200
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
$this->log( 'Info: `migrate_logs` Logs migrated: ' . $this->get_migrated_count(). ' Out of ' . wp_count_posts( 'postman_sent_mail' )->private );
|
||||
|
||||
wp_send_json_success(
|
||||
array(
|
||||
'migrated' => $this->get_migrated_count()
|
||||
),
|
||||
200
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Enqueue Scripts | Action call-back
|
||||
*
|
||||
* @since 2.5.0
|
||||
* @version 1.0.0
|
||||
*/
|
||||
public function enqueue_script() {
|
||||
|
||||
wp_enqueue_script( 'ps-migrate', POST_SMTP_URL . '/script/logs-migration.js', array( 'jquery' ), array(), true );
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get old logs
|
||||
*
|
||||
* @param $limit String
|
||||
* @since 2.5.0
|
||||
* @version 1.0.0
|
||||
*/
|
||||
public function get_old_logs( $limit = 500 ) {
|
||||
|
||||
global $wpdb;
|
||||
|
||||
$logs = $wpdb->get_results(
|
||||
$wpdb->prepare(
|
||||
"SELECT p.ID, p.post_date FROM {$wpdb->posts} AS p WHERE p.post_type = 'postman_sent_mail' && p.pinged != 1 LIMIT %d;",
|
||||
$limit
|
||||
),
|
||||
OBJECT_K
|
||||
);
|
||||
$log_ids = array_keys( $logs );
|
||||
$log_ids = implode( ',', $log_ids );
|
||||
|
||||
$this->log( 'Info: `get_old_logs` Log IDs: ' . $log_ids );
|
||||
|
||||
if( $log_ids ) {
|
||||
|
||||
$logs_meta = $wpdb->get_results(
|
||||
"SELECT post_id as ID, meta_key, meta_value FROM {$wpdb->postmeta} WHERE post_id IN ({$log_ids});"
|
||||
);
|
||||
|
||||
$this->log( 'Info: `get_old_logs` Logs Meta ' );
|
||||
|
||||
/**
|
||||
* Filter to delete incomplete logs, force migration
|
||||
*
|
||||
* @param bool
|
||||
* @since 2.5.0
|
||||
* @version 1.0.0
|
||||
*/
|
||||
if( empty( $logs_meta ) ) {
|
||||
|
||||
$this->log( 'Error: `get_old_logs` No logs meta found: ', $logs_meta );
|
||||
|
||||
$log_ids = explode( ',', $log_ids );
|
||||
|
||||
foreach( $log_ids as $ID ) {
|
||||
|
||||
$this->log( 'Error: `get_old_logs` Marking as pinged: ' . $ID );
|
||||
|
||||
wp_delete_post( $ID, true );
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
if( $logs_meta ) {
|
||||
|
||||
//Preparing logs
|
||||
foreach( $logs_meta as $log_meta ) {
|
||||
|
||||
if( isset( $prepared_logs[$log_meta->ID] ) ) {
|
||||
|
||||
$prepared_logs[$log_meta->ID][$log_meta->meta_key] = $log_meta->meta_value;
|
||||
|
||||
}
|
||||
else {
|
||||
|
||||
$prepared_logs[$log_meta->ID] = array(
|
||||
$log_meta->meta_key => $log_meta->meta_value,
|
||||
'time' => strtotime( $logs[$log_meta->ID]->post_date )
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$this->log( 'Info: `get_old_logs` Prepared Logs' );
|
||||
|
||||
return $prepared_logs;
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets migrated logs Count
|
||||
*
|
||||
* @since 2.5.0
|
||||
* @version 1.0.0
|
||||
*/
|
||||
public function get_migrated_count() {
|
||||
|
||||
global $wpdb;
|
||||
|
||||
$response = $wpdb->get_results(
|
||||
"SELECT
|
||||
count(*) AS count
|
||||
FROM
|
||||
{$wpdb->posts}
|
||||
WHERE
|
||||
post_type = 'postman_sent_mail'
|
||||
&&
|
||||
pinged = 1"
|
||||
);
|
||||
|
||||
return empty( $response ) ? false : (int)$response[0]->count;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Checks if logs migrated or not
|
||||
*
|
||||
* @since 2.5.0
|
||||
* @version 1.0.0
|
||||
*/
|
||||
public function is_migrated() {
|
||||
|
||||
$total_old_logs = wp_count_posts( 'postman_sent_mail' )->private;
|
||||
|
||||
if( $this->get_migrated_count() == (int)$total_old_logs ) {
|
||||
|
||||
delete_option( 'ps_migrate_logs' );
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Trash all old logs
|
||||
*
|
||||
* @since 2.5.0
|
||||
* @version 1.0.0
|
||||
*/
|
||||
public function trash_all_old_logs() {
|
||||
|
||||
if( wp_verify_nonce( $_GET['security'], 'ps-migrate-logs' ) ) {
|
||||
|
||||
global $wpdb;
|
||||
|
||||
$result = $wpdb->get_results(
|
||||
"SELECT ID
|
||||
FROM {$wpdb->posts}
|
||||
WHERE post_type = 'postman_sent_mail';",
|
||||
OBJECT_K
|
||||
);
|
||||
$log_ids = array_keys( $result );
|
||||
$log_ids = implode( ',', $log_ids );
|
||||
|
||||
$this->log( 'Info: `trash_all_old_logs` Delete log IDs: ' . $log_ids );
|
||||
|
||||
$result = $wpdb->get_results(
|
||||
"DELETE p.*, pm.*
|
||||
FROM {$wpdb->posts} AS p
|
||||
INNER JOIN
|
||||
{$wpdb->postmeta} AS pm
|
||||
ON p.ID = pm.post_id
|
||||
WHERE p.post_type = 'postman_sent_mail' && p.ID IN ({$log_ids});"
|
||||
);
|
||||
|
||||
$result = $result ? 'Successfully deleted' : 'Failed';
|
||||
|
||||
$this->log( 'Info: `trash_all_old_logs` Delete result: ' . print_r( $result, true ) );
|
||||
|
||||
//Delete log file
|
||||
if( file_exists( $this->logging_file ) ) {
|
||||
|
||||
unlink( $this->logging_file );
|
||||
|
||||
}
|
||||
|
||||
wp_redirect( admin_url( 'admin.php?page=postman_email_log' ) );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Switch back to old logs
|
||||
*
|
||||
* @since 2.5.0
|
||||
* @version 1.0.0
|
||||
*/
|
||||
public function switch_back() {
|
||||
|
||||
if( wp_verify_nonce( $_GET['security'], 'ps-migrate-logs' ) ) {
|
||||
|
||||
$this->log( 'Info: `switch_back` Switching to old system' );
|
||||
|
||||
delete_option( 'postman_db_version' );
|
||||
|
||||
wp_redirect( admin_url( 'admin.php?page=postman_email_log' ) );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Switch to new system
|
||||
*
|
||||
* @since 2.5.0
|
||||
* @version 1.0.0
|
||||
*/
|
||||
public function switch_to_new() {
|
||||
|
||||
if( wp_verify_nonce( $_GET['security'], 'ps-migrate-logs' ) ) {
|
||||
|
||||
$this->log( 'Info: `switch_to_new` Switching to new system' );
|
||||
|
||||
update_option( 'postman_db_version', POST_SMTP_DB_VERSION );
|
||||
|
||||
wp_redirect( admin_url( 'admin.php?page=postman_email_log' ) );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Remove Extra Keys
|
||||
*
|
||||
* @param array $array
|
||||
* @since 2.5.0
|
||||
* @version 1.0.0
|
||||
*/
|
||||
public function remove_extra_keys( $array ) {
|
||||
|
||||
$allowedKeys = array(
|
||||
'solution',
|
||||
'success',
|
||||
'from_header',
|
||||
'to_header',
|
||||
'cc_header',
|
||||
'bcc_header',
|
||||
'reply_to_header',
|
||||
'transport_uri',
|
||||
'original_to',
|
||||
'original_subject',
|
||||
'original_message',
|
||||
'original_headers',
|
||||
'session_transcript',
|
||||
'time'
|
||||
);
|
||||
|
||||
foreach ( $array as $key => $value ) {
|
||||
|
||||
if ( !in_array( $key, $allowedKeys ) ) {
|
||||
|
||||
unset( $array[$key] );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return $array;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create log file
|
||||
*
|
||||
* @since 2.5.0
|
||||
* @version 1.0.0
|
||||
*/
|
||||
public function create_log_file() {
|
||||
|
||||
if( !file_exists( $this->logging_file ) ) {
|
||||
|
||||
$site_url = site_url();
|
||||
$logging = fopen( $this->logging_file, 'w' );
|
||||
|
||||
if( $logging ) {
|
||||
|
||||
fwrite( $logging, 'Migration log: ' . $site_url . PHP_EOL );
|
||||
fwrite( $logging, 'Info, Error' . PHP_EOL );
|
||||
fclose( $logging );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Write to log file | Info and Error, only two types
|
||||
*
|
||||
* @param string $message
|
||||
* @since 2.5.0
|
||||
* @version 1.0.0
|
||||
*/
|
||||
public function log( $message ) {
|
||||
|
||||
if( !file_exists( $this->logging_file ) ) {
|
||||
|
||||
$this->create_log_file();
|
||||
|
||||
}
|
||||
if( file_exists( $this->logging_file ) ) {
|
||||
|
||||
$logging = fopen( $this->logging_file, 'a' );
|
||||
if( $logging ) {
|
||||
|
||||
fwrite( $logging, '[' . date( 'd-m-Y h:i:s' ) . '] ->' . $message . PHP_EOL );
|
||||
fclose( $logging );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if logs migrated or not | Same as is_migrated() but used custom query
|
||||
*
|
||||
* @since 2.5.2
|
||||
* @version 1.0.0
|
||||
*/
|
||||
public function has_migrated() {
|
||||
|
||||
global $wpdb;
|
||||
|
||||
$response = $wpdb->get_results(
|
||||
"SELECT
|
||||
count(*) AS count
|
||||
FROM
|
||||
{$wpdb->posts}
|
||||
WHERE
|
||||
post_type = 'postman_sent_mail'"
|
||||
);
|
||||
|
||||
$total_old_logs = empty( $response ) ? 0 : (int)$response[0]->count;
|
||||
|
||||
if( $this->get_migrated_count() >= (int)$total_old_logs ) {
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Dismiss update notice | AJAX call-back
|
||||
*
|
||||
* @since 2.5.2
|
||||
* @version 1.0.0
|
||||
*/
|
||||
public function dismiss_update_notice() {
|
||||
|
||||
if( isset( $_POST['action'] ) && $_POST['action'] == 'ps-db-update-notice-dismiss' && wp_verify_nonce( $_POST['security'], 'ps-migrate-logs' ) ) {
|
||||
|
||||
set_transient( 'ps_dismiss_update_notice', 1, WEEK_IN_SECONDS );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Revert migration
|
||||
*
|
||||
* @since 2.5.2
|
||||
* @version 1.0.0
|
||||
*/
|
||||
public function revert_migration() {
|
||||
|
||||
if( wp_verify_nonce( $_GET['security'], 'ps-migrate-logs' ) ) {
|
||||
|
||||
$this->log( 'Info: `revert_migration` Reverting Migration' );
|
||||
$email_logs = new PostmanEmailLogs;
|
||||
|
||||
delete_option( 'ps_migrate_logs' );
|
||||
$this->log( 'Info: `revert_migration` Deleted option ps_migrate_logs' );
|
||||
|
||||
if( $email_logs->uninstall_tables() ) {
|
||||
|
||||
$this->log( 'Info: `revert_migration` Tables Uninstalled' );
|
||||
|
||||
global $wpdb;
|
||||
$response = $wpdb->query(
|
||||
"UPDATE {$wpdb->posts} SET pinged = '' WHERE post_type = 'postman_sent_mail';"
|
||||
);
|
||||
|
||||
if( $response ) {
|
||||
|
||||
$this->log( 'Info: `revert_migration` pinged unset' );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
wp_redirect( admin_url( 'admin.php?page=postman_email_log' ) );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Skip migration
|
||||
*
|
||||
* @since 2.5.2
|
||||
* @version 1.0.0
|
||||
*/
|
||||
public function skip_migration() {
|
||||
|
||||
if( wp_verify_nonce( $_GET['security'], 'ps-migrate-logs' ) ) {
|
||||
|
||||
$this->log( 'Info: `skip_migration` Skipping Migration' );
|
||||
|
||||
delete_option( 'ps_migrate_logs' );
|
||||
$this->log( 'Info: `skip_migration` Deleted option ps_migrate_logs' );
|
||||
|
||||
$email_logs = new PostmanEmailLogs;
|
||||
$email_logs->install_table();
|
||||
|
||||
$this->log( 'Info: Table created' );
|
||||
|
||||
global $wpdb;
|
||||
|
||||
$result = $wpdb->get_results(
|
||||
"SELECT ID
|
||||
FROM {$wpdb->posts}
|
||||
WHERE post_type = 'postman_sent_mail';",
|
||||
OBJECT_K
|
||||
);
|
||||
$log_ids = array_keys( $result );
|
||||
$log_ids = implode( ',', $log_ids );
|
||||
|
||||
$this->log( 'Info: `trash_all_old_logs` Delete log IDs: ' . $log_ids );
|
||||
|
||||
$result = $wpdb->get_results(
|
||||
"DELETE p.*, pm.*
|
||||
FROM {$wpdb->posts} AS p
|
||||
INNER JOIN
|
||||
{$wpdb->postmeta} AS pm
|
||||
ON p.ID = pm.post_id
|
||||
WHERE p.post_type = 'postman_sent_mail' && p.ID IN ({$log_ids});"
|
||||
);
|
||||
|
||||
$result = $result ? 'Successfully deleted' : 'Failed';
|
||||
|
||||
$this->log( 'Info: `trash_all_old_logs` Delete result: ' . print_r( $result, true ) );
|
||||
|
||||
wp_redirect( admin_url( 'admin.php?page=postman_email_log' ) );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
new PostmanEmailLogsMigration;
|
||||
|
||||
endif;
|
||||
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
if (! class_exists ( 'PostmanEmailLogPostType' )) {
|
||||
|
||||
/**
|
||||
* This class creates the Custom Post Type for Email Logs and handles writing these posts.
|
||||
*
|
||||
* @author jasonhendriks
|
||||
*/
|
||||
class PostmanEmailLogPostType {
|
||||
|
||||
// constants
|
||||
const POSTMAN_CUSTOM_POST_TYPE_SLUG = 'postman_sent_mail';
|
||||
|
||||
/**
|
||||
* Behavior to run on the WordPress 'init' action
|
||||
*/
|
||||
public static function automaticallyCreatePostType() {
|
||||
add_action ( 'init', array (
|
||||
new PostmanEmailLogPostType (),
|
||||
'create_post_type'
|
||||
) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a custom post type
|
||||
* Callback function - must be public scope
|
||||
*
|
||||
* register_post_type should only be invoked through the 'init' action.
|
||||
* It will not work if called before 'init', and aspects of the newly
|
||||
* created or modified post type will work incorrectly if called later.
|
||||
*
|
||||
* https://codex.wordpress.org/Function_Reference/register_post_type
|
||||
*/
|
||||
public static function create_post_type() {
|
||||
register_post_type ( self::POSTMAN_CUSTOM_POST_TYPE_SLUG, array (
|
||||
'labels' => array (
|
||||
'name' => _x ( 'Sent Emails', 'The group of Emails that have been delivered', 'post-smtp' ),
|
||||
'singular_name' => _x ( 'Sent Email', 'An Email that has been delivered', 'post-smtp' )
|
||||
),
|
||||
'capability_type' => '',
|
||||
'capabilities' => array ()
|
||||
) );
|
||||
$logger = new PostmanLogger ( 'PostmanEmailLogPostType' );
|
||||
$logger->trace ( 'Created post type: ' . self::POSTMAN_CUSTOM_POST_TYPE_SLUG );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,542 @@
|
||||
<?php
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
require_once dirname(__DIR__ ) . '/PostmanLogFields.php';
|
||||
require_once POST_SMTP_PATH . '/Postman/Extensions/Core/Notifications/PostmanNotify.php';
|
||||
require_once POST_SMTP_PATH . '/Postman/Extensions/Core/StatusSolution.php';
|
||||
require_once POST_SMTP_PATH . '/Postman/PostmanEmailLogs.php';
|
||||
|
||||
if ( ! class_exists( 'PostmanEmailLog' ) ) {
|
||||
class PostmanEmailLog {
|
||||
public $sender;
|
||||
public $toRecipients;
|
||||
public $ccRecipients;
|
||||
public $bccRecipients;
|
||||
public $subject;
|
||||
public $body;
|
||||
public $success;
|
||||
public $statusMessage;
|
||||
public $sessionTranscript;
|
||||
public $transportUri;
|
||||
public $replyTo;
|
||||
public $originalTo;
|
||||
public $originalSubject;
|
||||
public $originalMessage;
|
||||
public $originalHeaders;
|
||||
|
||||
public function setStatusMessage( $message ) {
|
||||
$this->statusMessage .= $message;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! class_exists( 'PostmanEmailLogService' ) ) {
|
||||
|
||||
/**
|
||||
* This class creates the Custom Post Type for Email Logs and handles writing these posts.
|
||||
*
|
||||
* @author jasonhendriks
|
||||
*/
|
||||
class PostmanEmailLogService {
|
||||
|
||||
/*
|
||||
* Private content is published only for your eyes, or the eyes of only those with authorization
|
||||
* permission levels to see private content. Normal users and visitors will not be aware of
|
||||
* private content. It will not appear in the article lists. If a visitor were to guess the URL
|
||||
* for your private post, they would still not be able to see your content. You will only see
|
||||
* the private content when you are logged into your WordPress blog.
|
||||
*/
|
||||
const POSTMAN_CUSTOM_POST_STATUS_PRIVATE = 'private';
|
||||
|
||||
// member variables
|
||||
private $logger;
|
||||
private $inst;
|
||||
public $new_logging = false;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
private function __construct() {
|
||||
|
||||
$this->logger = new PostmanLogger( get_class( $this ) );
|
||||
$this->new_logging = get_option( 'postman_db_version' );
|
||||
|
||||
add_action('post_smtp_on_success', array( $this, 'write_success_log' ), 10, 4 );
|
||||
add_action('post_smtp_on_failed', array( $this, 'write_failed_log' ), 10, 5 );
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* singleton instance
|
||||
*/
|
||||
public static function getInstance() {
|
||||
static $inst = null;
|
||||
if ( $inst === null ) {
|
||||
$inst = new PostmanEmailLogService();
|
||||
}
|
||||
return $inst;
|
||||
}
|
||||
|
||||
public function write_success_log( $log, $message, $transcript, $transport = null ) {
|
||||
$options = PostmanOptions::getInstance();
|
||||
if ( $options->getRunMode() == PostmanOptions::RUN_MODE_PRODUCTION || $options->getRunMode() == PostmanOptions::RUN_MODE_LOG_ONLY ) {
|
||||
$this->writeSuccessLog( $log, $message, $transcript, $transport );
|
||||
}
|
||||
}
|
||||
|
||||
public function write_failed_log( $log, $message, $transcript, $transport = null, $statusMessage = null ) {
|
||||
$options = PostmanOptions::getInstance();
|
||||
if ( $options->getRunMode() == PostmanOptions::RUN_MODE_PRODUCTION || $options->getRunMode() == PostmanOptions::RUN_MODE_LOG_ONLY ) {
|
||||
$this->writeFailureLog( $log, $transcript, $statusMessage, $transport, $message );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs successful email attempts
|
||||
*
|
||||
* @param PostmanMessage $message
|
||||
* @param mixed $transcript
|
||||
* @param PostmanModuleTransport|null $transport
|
||||
*/
|
||||
public function writeSuccessLog( PostmanEmailLog $log, PostmanMessage $message, $transcript, ?PostmanModuleTransport $transport = null ) {
|
||||
if ( PostmanOptions::getInstance()->isMailLoggingEnabled() ) {
|
||||
$statusMessage = '';
|
||||
$status = true;
|
||||
$subject = $message->getSubject();
|
||||
if ( empty( $subject ) ) {
|
||||
$statusMessage = sprintf( '%s: %s', __( 'Warning', 'post-smtp' ), __( 'An empty subject line can result in delivery failure.', 'post-smtp' ) );
|
||||
$status = 'WARN';
|
||||
}
|
||||
|
||||
$logger = $this->logger;
|
||||
if ( is_null( $transport ) ) {
|
||||
$logger->warn( 'writeSuccessLog called with null transport' );
|
||||
}
|
||||
|
||||
$this->createLog( $log, $transcript, $statusMessage, $status, $transport, $message );
|
||||
$this->writeToEmailLog( $log );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs failed email attempts, requires more metadata so the email can be resent in the future
|
||||
*
|
||||
* @param PostmanMessage $message
|
||||
* @param mixed $transcript
|
||||
* @param mixed $statusMessage
|
||||
* @param mixed $originalTo
|
||||
* @param mixed $originalSubject
|
||||
* @param mixed $originalMessage
|
||||
* @param PostmanModuleTransport|null $transport
|
||||
* @param mixed $originalHeaders
|
||||
*/
|
||||
public function writeFailureLog( PostmanEmailLog $log, $transcript, $statusMessage, ?PostmanModuleTransport $transport = null, ?PostmanMessage $message = null ) {
|
||||
if ( PostmanOptions::getInstance()->isMailLoggingEnabled() ) {
|
||||
|
||||
if ( is_null( $transport ) ) {
|
||||
$this->logger->warn( 'writeFailureLog called with null transport' );
|
||||
}
|
||||
|
||||
$this->createLog( $log, $transcript, $statusMessage, false, $transport, $message );
|
||||
$this->writeToEmailLog( $log,$message );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitizes a list of emails, handling both single and multiple email inputs.
|
||||
*
|
||||
* @param string|array $emails The email(s) to sanitize.
|
||||
* @return string Sanitized email(s) as a comma-separated string.
|
||||
* @since 3.1.2
|
||||
* @version 1.0.0
|
||||
*/
|
||||
public function sanitize_emails( $emails ) {
|
||||
if ( empty( $emails ) ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// Convert string to an array if necessary.
|
||||
if ( is_string( $emails ) ) {
|
||||
$emails = explode( ',', $emails );
|
||||
}
|
||||
|
||||
if ( ! is_array( $emails ) ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$sanitized_emails = array_map( function ( $email ) {
|
||||
$email = trim( $email );
|
||||
|
||||
// Extract email from "Name <email>" format.
|
||||
if ( preg_match( '/<(.+?)>/', $email, $matches ) ) {
|
||||
$email = $matches[1];
|
||||
}
|
||||
|
||||
return filter_var( $email, FILTER_VALIDATE_EMAIL ) ? sanitize_email( $email ) : '';
|
||||
}, $emails );
|
||||
|
||||
// Remove duplicates and empty values
|
||||
$sanitized_emails = array_unique( array_filter( $sanitized_emails ) );
|
||||
|
||||
return implode( ', ', $sanitized_emails );
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes an email sending attempt to the Email Log
|
||||
*
|
||||
* From http://wordpress.stackexchange.com/questions/8569/wp-insert-post-php-function-and-custom-fields
|
||||
*/
|
||||
private function writeToEmailLog( PostmanEmailLog $log, ?PostmanMessage $message = null ) {
|
||||
|
||||
$options = PostmanOptions::getInstance();
|
||||
|
||||
$new_status = $log->statusMessage;
|
||||
|
||||
if ( $options->is_fallback && empty( $log->statusMessage ) ) {
|
||||
$new_status = 'Sent ( ** Fallback ** )';
|
||||
}
|
||||
|
||||
if ( $options->is_fallback && ! empty( $log->statusMessage ) ) {
|
||||
// $new_status = '( ** Fallback ** ) ' . $log->statusMessage;
|
||||
$new_status = $log->statusMessage;
|
||||
}
|
||||
|
||||
$new_status = apply_filters( 'post_smtp_log_status', $new_status, $log, $message );
|
||||
//If Table exists, Insert Log into Table
|
||||
if( $this->new_logging ) {
|
||||
$data = array();
|
||||
$data['solution'] = apply_filters( 'post_smtp_log_solution', null, $new_status, $log, $message );
|
||||
// The filtering logic will handle both success = 1 and fallback status messages
|
||||
if ( $log->success === true || $log->success === 'WARN' || $log->success === 1 ) {
|
||||
$data['success'] = empty( $new_status ) ? 1 : $new_status;
|
||||
} else {
|
||||
$data['success'] = empty( $new_status ) ? 0 : $new_status;
|
||||
}
|
||||
$data['from_header'] = $log->sender;
|
||||
$data['to_header'] = $this->sanitize_emails( $log->toRecipients );
|
||||
$data['cc_header'] = $this->sanitize_emails( $log->ccRecipients );
|
||||
$data['bcc_header'] = $this->sanitize_emails( $log->bccRecipients );
|
||||
$data['reply_to_header'] = $this->sanitize_emails( $log->replyTo );
|
||||
$data['transport_uri'] = !empty( $log->transportUri ) ? $log->transportUri : '';
|
||||
$data['original_to'] = $this->sanitize_emails( $log->originalTo );
|
||||
$data['original_subject'] = !empty( $log->originalSubject ) ? sanitize_text_field( $log->originalSubject ) : '';
|
||||
$data['original_message'] = $log->originalMessage;
|
||||
$data['original_headers'] = is_array( $log->originalHeaders ) ? serialize( $log->originalHeaders ) : $log->originalHeaders;
|
||||
$data['session_transcript'] = $log->sessionTranscript;
|
||||
|
||||
$email_logs = new PostmanEmailLogs();
|
||||
|
||||
/**
|
||||
* Filter the email log id
|
||||
*
|
||||
* @param string $log_id
|
||||
* @since 2.5.0
|
||||
* @version 1.0.0
|
||||
*/
|
||||
$log_id = apply_filters( 'post_smtp_update_email_log_id', '' );
|
||||
$log_id = $email_logs->save( $data, $log_id );
|
||||
|
||||
/**
|
||||
* Fires after the email log is saved
|
||||
*
|
||||
* @param string $log_id
|
||||
* @since 2.5.0
|
||||
* @version 1.0.0
|
||||
*/
|
||||
|
||||
do_action( 'post_smtp_after_email_log_saved', $log_id );
|
||||
|
||||
$this->logger->debug( sprintf( 'Saved message #%s to the database', $log_id ) );
|
||||
$this->logger->trace( $log );
|
||||
|
||||
}
|
||||
//Do as previous
|
||||
else {
|
||||
|
||||
// nothing here is sanitized as WordPress should take care of
|
||||
// making database writes safe
|
||||
$my_post = array(
|
||||
'post_type' => PostmanEmailLogPostType::POSTMAN_CUSTOM_POST_TYPE_SLUG,
|
||||
'post_title' => $log->subject,
|
||||
'post_content' => $log->body,
|
||||
'post_excerpt' => $new_status,
|
||||
'post_status' => PostmanEmailLogService::POSTMAN_CUSTOM_POST_STATUS_PRIVATE,
|
||||
);
|
||||
|
||||
// Insert the post into the database (WordPress gives us the Post ID)
|
||||
$post_id = wp_insert_post( $my_post, true );
|
||||
|
||||
if ( is_wp_error( $post_id ) ) {
|
||||
add_action( 'admin_notices', function() use( $post_id ) {
|
||||
$class = 'notice notice-error';
|
||||
$message = $post_id->get_error_message();
|
||||
|
||||
printf( '<div class="%1$s"><p>%2$s</p></div>', esc_attr( $class ), esc_html( $message ) );
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->logger->debug( sprintf( 'Saved message #%s to the database', $post_id ) );
|
||||
$this->logger->trace( $log );
|
||||
|
||||
$solution = apply_filters( 'post_smtp_log_solution', null, $new_status, $log, $message );
|
||||
|
||||
// Write the meta data related to the email
|
||||
PostmanLogFields::get_instance()->update( $post_id, 'solution', $solution );
|
||||
PostmanLogFields::get_instance()->update( $post_id, 'success', $log->success );
|
||||
PostmanLogFields::get_instance()->update( $post_id, 'from_header', $log->sender );
|
||||
if ( ! empty( $log->toRecipients ) ) {
|
||||
PostmanLogFields::get_instance()->update( $post_id, 'to_header', $log->toRecipients );
|
||||
}
|
||||
if ( ! empty( $log->ccRecipients ) ) {
|
||||
PostmanLogFields::get_instance()->update( $post_id, 'cc_header', $log->ccRecipients );
|
||||
}
|
||||
if ( ! empty( $log->bccRecipients ) ) {
|
||||
PostmanLogFields::get_instance()->update( $post_id, 'bcc_header', $log->bccRecipients );
|
||||
}
|
||||
if ( ! empty( $log->replyTo ) ) {
|
||||
PostmanLogFields::get_instance()->update( $post_id, 'reply_to_header', $log->replyTo );
|
||||
}
|
||||
PostmanLogFields::get_instance()->update( $post_id, 'transport_uri', $log->transportUri );
|
||||
|
||||
if ( ! $log->success || true ) {
|
||||
// alwas add the meta data so we can re-send it
|
||||
PostmanLogFields::get_instance()->update( $post_id, 'original_to', $log->originalTo );
|
||||
PostmanLogFields::get_instance()->update( $post_id, 'original_subject', $log->originalSubject );
|
||||
PostmanLogFields::get_instance()->update( $post_id, 'original_message', $log->originalMessage );
|
||||
PostmanLogFields::get_instance()->update( $post_id, 'original_headers', $log->originalHeaders );
|
||||
}
|
||||
|
||||
// we do not sanitize the session transcript - let the reader decide how to handle the data
|
||||
PostmanLogFields::get_instance()->update( $post_id, 'session_transcript', $log->sessionTranscript );
|
||||
|
||||
}
|
||||
|
||||
// truncate the log (remove older entries)
|
||||
$purger = new PostmanEmailLogPurger();
|
||||
|
||||
/**
|
||||
* Filter whether to truncate the log
|
||||
*
|
||||
* @param bool $truncate
|
||||
* @since 2.6.1
|
||||
* @version 1.0.0
|
||||
*/
|
||||
if( apply_filters( 'post_smtp_truncate_the_log', true ) ) {
|
||||
|
||||
$purger->truncateLogItems( PostmanOptions::getInstance()->getMailLoggingMaxEntries() );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Log object for use by writeToEmailLog()
|
||||
*
|
||||
* @param PostmanMessage $message
|
||||
* @param mixed $transcript
|
||||
* @param mixed $statusMessage
|
||||
* @param mixed $success
|
||||
* @param PostmanModuleTransport|null $transport
|
||||
* @return PostmanEmailLog
|
||||
*/
|
||||
private function createLog( PostmanEmailLog $log, $transcript, $statusMessage, $success, ?PostmanModuleTransport $transport, ?PostmanMessage $message = null ) {
|
||||
if ( $message ) {
|
||||
$log->sender = $message->getFromAddress()->format();
|
||||
$log->toRecipients = $this->flattenEmails( $message->getToRecipients() );
|
||||
$log->ccRecipients = $this->flattenEmails( $message->getCcRecipients() );
|
||||
$log->bccRecipients = $this->flattenEmails( $message->getBccRecipients() );
|
||||
$log->subject = $message->getSubject();
|
||||
$log->body = $message->getBody();
|
||||
if ( null !== $message->getReplyTo() ) {
|
||||
$log->replyTo = $message->getReplyTo()->format();
|
||||
}
|
||||
}
|
||||
$log->success = $success;
|
||||
$log->statusMessage = $statusMessage;
|
||||
if ( $transport ) {
|
||||
$log->transportUri = PostmanTransportRegistry::getInstance()->getPublicTransportUri( $transport );
|
||||
$log->sessionTranscript = $log->transportUri . "\n\n" . $transcript;
|
||||
} else {
|
||||
$log->transportUri = '';
|
||||
$log->sessionTranscript = $transcript;
|
||||
}
|
||||
return $log;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a readable "TO" entry based on the recipient header
|
||||
*
|
||||
* @param array $addresses
|
||||
* @return string
|
||||
*/
|
||||
private static function flattenEmails( array $addresses ) {
|
||||
$flat = '';
|
||||
$count = 0;
|
||||
foreach ( $addresses as $address ) {
|
||||
if ( $count >= 3 ) {
|
||||
$flat .= sprintf( __( '.. +%d more', 'post-smtp' ), sizeof( $addresses ) - $count );
|
||||
break;
|
||||
}
|
||||
if ( $count > 0 ) {
|
||||
$flat .= ', ';
|
||||
}
|
||||
$flat .= $address->format();
|
||||
$count ++;
|
||||
}
|
||||
return $flat;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! class_exists( 'PostmanEmailLogPurger' ) ) {
|
||||
class PostmanEmailLogPurger {
|
||||
|
||||
private $logs;
|
||||
private $logger;
|
||||
private $new_logging;
|
||||
private $email_logs;
|
||||
|
||||
/**
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
function __construct() {
|
||||
|
||||
$this->new_logging = get_option( 'postman_db_version' );
|
||||
|
||||
$this->get_logs();
|
||||
$this->email_logs = new PostmanEmailLogs();
|
||||
$this->logger = new PostmanLogger( get_class( $this ) );
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get Logs
|
||||
*
|
||||
* @since 2.5.0
|
||||
* @version 1.0.0
|
||||
*/
|
||||
public function get_logs() {
|
||||
|
||||
if( !$this->new_logging ) {
|
||||
|
||||
$this->get_old_logs();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets Logs From _posts table
|
||||
*
|
||||
* @since 2.5.0
|
||||
* @version 1.0.0
|
||||
*/
|
||||
public function get_old_logs() {
|
||||
|
||||
$args = array(
|
||||
'posts_per_page' => -1,
|
||||
'offset' => 0,
|
||||
'category' => '',
|
||||
'category_name' => '',
|
||||
'orderby' => 'date',
|
||||
'order' => 'DESC',
|
||||
'include' => '',
|
||||
'exclude' => '',
|
||||
'meta_key' => '',
|
||||
'meta_value' => '',
|
||||
'post_type' => PostmanEmailLogPostType::POSTMAN_CUSTOM_POST_TYPE_SLUG,
|
||||
'post_mime_type' => '',
|
||||
'post_parent' => '',
|
||||
'post_status' => 'private',
|
||||
'suppress_filters' => true,
|
||||
);
|
||||
|
||||
$query = new WP_Query( $args );
|
||||
$this->logs = $query->posts;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get logs from _post_smtp_logs table
|
||||
*
|
||||
* @since 2.5.0
|
||||
* @version 1.0.0
|
||||
*/
|
||||
public function get_new_logs() {
|
||||
|
||||
$logs = new PostmanEmailLogs();
|
||||
$this->logs = $logs->get_logs();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param array $posts
|
||||
* @param mixed $postid
|
||||
*/
|
||||
function verifyLogItemExistsAndRemove( $postid ) {
|
||||
$force_delete = true;
|
||||
foreach ( $this->logs as $post ) {
|
||||
if ( $post->ID == $postid ) {
|
||||
$this->logger->debug( 'deleting log item ' . intval( $postid ) );
|
||||
wp_delete_post( $postid, $force_delete );
|
||||
return;
|
||||
}
|
||||
}
|
||||
$this->logger->warn( 'could not find Postman Log Item #' . $postid );
|
||||
}
|
||||
function removeAll() {
|
||||
|
||||
if( $this->new_logging ) {
|
||||
|
||||
$email_query_log = new PostmanEmailQueryLog();
|
||||
$delete = $email_query_log->delete_logs( array( -1 ) );
|
||||
$this->logger->debug( sprintf( 'Delete Response: %s', $delete ) );
|
||||
|
||||
}
|
||||
else {
|
||||
|
||||
$this->logger->debug( sprintf( 'deleting %d log items ', sizeof( $this->logs ) ) );
|
||||
$force_delete = true;
|
||||
foreach ( $this->logs as $post ) {
|
||||
wp_delete_post( $post->ID, $force_delete );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param mixed $size
|
||||
*/
|
||||
function truncateLogItems( $size ) {
|
||||
|
||||
if( $this->new_logging ) {
|
||||
|
||||
$this->email_logs->truncate_log_items( $size );
|
||||
|
||||
}
|
||||
else {
|
||||
|
||||
$index = count( $this->logs );
|
||||
$force_delete = true;
|
||||
while ( $index > $size ) {
|
||||
$postid = $this->logs [ -- $index ]->ID;
|
||||
$this->logger->debug( 'deleting log item ' . $postid );
|
||||
wp_delete_post( $postid, $force_delete );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
<div class="wrap">
|
||||
<h1>Post SMTP Email Logs</h1>
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Fires before the logs table.
|
||||
*
|
||||
* @since 2.6.1
|
||||
* @version 1.0.0
|
||||
*/
|
||||
do_action( 'post_smtp_before_logs_table' );
|
||||
?>
|
||||
<input type="hidden" id="ps-email-log-nonce" value="<?php echo wp_create_nonce( 'security' ) ?>" />
|
||||
<table width="100%" id="ps-email-log">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><input type="checkbox" class="ps-email-log-select-all" /></th>
|
||||
<th>Subject</th>
|
||||
<th>Sent To</th>
|
||||
<th>Delivery Time</th>
|
||||
<th>Status</th>
|
||||
<th class="ps-email-log-actions">Actions</th>
|
||||
<?php do_action( 'post_smtp_email_logs_table_header' ); ?>
|
||||
</tr>
|
||||
</thead>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<th><input type="checkbox" class="ps-email-log-select-all" /></th>
|
||||
<th>Subject</th>
|
||||
<th>Sent To</th>
|
||||
<th>Delivery Time</th>
|
||||
<th>Status</th>
|
||||
<th class="ps-email-log-actions">Actions</th>
|
||||
<?php do_action( 'post_smtp_email_logs_table_header' ); ?>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
|
||||
<div class="ps-popup-wrap">
|
||||
<div class="ps-popup-box" <?php echo postman_is_bfcm() ? 'style="height: 512px";' : ''; ?>>
|
||||
<a class="ps-popup-close-btn ps-popup-close" href="#"><span class="dashicons dashicons-no-alt"></span></a>
|
||||
<div class="ps-popup-container"></div>
|
||||
<?php
|
||||
if( postman_is_bfcm() ) {
|
||||
|
||||
?>
|
||||
<a href="https://postmansmtp.com/cyber-monday-sale?utm_source=plugin&utm_medium=section_name&utm_campaign=BFCM&utm_id=BFCM_2024" target="_blank">
|
||||
<img src="<?php echo esc_url( POST_SMTP_ASSETS . 'images/bfcm-2024/dashboard.png' ) ?>" style="width: 100%;" />
|
||||
</a>
|
||||
<a href="<?php echo admin_url( 'admin.php?action=ps-skip-bfcm' ); ?>" style="font-size: 10px;">Not interested, Hide for now.</a>
|
||||
<?php
|
||||
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,454 @@
|
||||
<?php
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
require_once dirname(__DIR__) . '/PostmanLogFields.php';
|
||||
|
||||
/**
|
||||
* See http://wpengineer.com/2426/wp_list_table-a-step-by-step-guide/
|
||||
*/
|
||||
if ( ! class_exists( 'WP_List_Table' ) ) {
|
||||
require_once( ABSPATH . 'wp-admin/includes/class-wp-list-table.php' );
|
||||
}
|
||||
class PostmanEmailLogView extends WP_List_Table {
|
||||
private $logger;
|
||||
|
||||
/**
|
||||
* ************************************************************************
|
||||
* REQUIRED.
|
||||
* Set up a constructor that references the parent constructor. We
|
||||
* use the parent reference to set some default configs.
|
||||
* *************************************************************************
|
||||
*/
|
||||
function __construct() {
|
||||
$this->logger = new PostmanLogger( get_class( $this ) );
|
||||
|
||||
// Set parent defaults
|
||||
parent::__construct( array(
|
||||
'singular' => 'email_log_entry', // singular name of the listed records
|
||||
'plural' => 'email_log_entries', // plural name of the listed records
|
||||
'ajax' => false,
|
||||
) ); // does this table support ajax?
|
||||
}
|
||||
|
||||
/**
|
||||
* ************************************************************************
|
||||
* Recommended.
|
||||
* This method is called when the parent class can't find a method
|
||||
* specifically build for a given column. Generally, it's recommended to include
|
||||
* one method for each column you want to render, keeping your package class
|
||||
* neat and organized. For example, if the class needs to process a column
|
||||
* named 'title', it would first see if a method named $this->column_title()
|
||||
* exists - if it does, that method will be used. If it doesn't, this one will
|
||||
* be used. Generally, you should try to use custom column methods as much as
|
||||
* possible.
|
||||
*
|
||||
* Since we have defined a column_title() method later on, this method doesn't
|
||||
* need to concern itself with any column with a name of 'title'. Instead, it
|
||||
* needs to handle everything else.
|
||||
*
|
||||
* For more detailed insight into how columns are handled, take a look at
|
||||
* WP_List_Table::single_row_columns()
|
||||
*
|
||||
* @param array $item
|
||||
* A singular item (one full row's worth of data)
|
||||
* @param array $column_name
|
||||
* The name/slug of the column to be processed
|
||||
* @return string Text or HTML to be placed inside the column <td>
|
||||
* ************************************************************************
|
||||
*/
|
||||
function column_default( $item, $column_name ) {
|
||||
switch ( $column_name ) {
|
||||
case 'sent_to' :
|
||||
case 'solution' :
|
||||
case 'date' :
|
||||
case 'status' :
|
||||
return $item [ $column_name ];
|
||||
default :
|
||||
return print_r( $item, true ); // Show the whole array for troubleshooting purposes
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ************************************************************************
|
||||
* Recommended.
|
||||
* This is a custom column method and is responsible for what
|
||||
* is rendered in any column with a name/slug of 'title'. Every time the class
|
||||
* needs to render a column, it first looks for a method named
|
||||
* column_{$column_title} - if it exists, that method is run. If it doesn't
|
||||
* exist, column_default() is called instead.
|
||||
*
|
||||
* This example also illustrates how to implement rollover actions. Actions
|
||||
* should be an associative array formatted as 'slug'=>'link html' - and you
|
||||
* will need to generate the URLs yourself. You could even ensure the links
|
||||
*
|
||||
* @see WP_List_Table::::single_row_columns()
|
||||
* @param array $item
|
||||
* A singular item (one full row's worth of data)
|
||||
* @return string Text to be placed inside the column <td> (movie title only)
|
||||
* ************************************************************************
|
||||
*/
|
||||
function column_title( $item ) {
|
||||
|
||||
// Build row actions
|
||||
$iframeUri = 'admin-post.php?page=postman_email_log&action=%s&email=%s&TB_iframe=true&width=700&height=550';
|
||||
$deleteUrl = wp_nonce_url( admin_url( sprintf( 'admin-post.php?page=postman_email_log&action=%s&email=%s', 'delete', $item ['ID'] ) ), 'delete_email_log_item_' . $item ['ID'] );
|
||||
$viewUrl = admin_url( sprintf( $iframeUri, 'view', $item ['ID'] ) );
|
||||
$transcriptUrl = admin_url( sprintf( $iframeUri, 'transcript', $item ['ID'] ) );
|
||||
$resendUrl = admin_url( sprintf( $iframeUri, 'resend', $item ['ID'] ) );
|
||||
|
||||
$meta_values = PostmanLogFields::get_instance()->get( $item ['ID'] );
|
||||
|
||||
$actions = array(
|
||||
'delete' => sprintf( '<a href="%s">%s</a>', $deleteUrl, _x( 'Delete', 'Delete an item from the email log', 'post-smtp' ) ),
|
||||
'view' => sprintf( '<a href="%s" class="thickbox">%s</a>', $viewUrl, _x( 'View', 'View an item from the email log', 'post-smtp' ) ),
|
||||
);
|
||||
|
||||
if ( ! empty( $meta_values ['session_transcript'] [0] ) ) {
|
||||
$actions ['transcript'] = sprintf( '<a href="%1$s" class="thickbox">%2$s</a>', $transcriptUrl, __( 'Session Transcript', 'post-smtp' ) );
|
||||
} else {
|
||||
$actions ['transcript'] = sprintf( '%2$s', $transcriptUrl, __( 'Session Transcript', 'post-smtp' ) );
|
||||
}
|
||||
if ( ! (empty( $meta_values ['original_to'] [0] ) && empty( $meta_values ['originalHeaders'] [0] )) ) {
|
||||
// $actions ['resend'] = sprintf ( '<a href="%s">%s</a>', $resendUrl, __ ( 'Resend', 'post-smtp' ) );
|
||||
$emails = $meta_values ['original_to'] [0];
|
||||
$to = !is_array( $emails ) ? explode( ',', $emails ) : $emails;
|
||||
$to = array_map( 'sanitize_email', $to );
|
||||
$to = implode( ',', $to );
|
||||
|
||||
$actions ['resend'] = sprintf( '<span id="%3$s"><a class="postman-open-resend" href="#">%2$s</a></span><div style="display:none;"><input type="hidden" name="security" value="%6$s"><input type="text" name="mail_to" class="regular-text ltr" data-id="%1$s" value="%4$s"><button class="postman-resend button button-primary">%2$s</button><i style="color: black;">%5$s</i></div>', $item ['ID'], __( 'Resend', 'post-smtp' ), 'resend-' . $item ['ID'], esc_attr( $to ), __( 'comma-separated for multiple emails', 'post-smtp' ), wp_create_nonce( 'resend' ) );
|
||||
} else {
|
||||
$actions ['resend'] = sprintf( '%2$s', $resendUrl, __( 'Resend', 'post-smtp' ) );
|
||||
}
|
||||
|
||||
// Return the title contents
|
||||
return sprintf( '%1$s %3$s',
|
||||
/*$1%s*/ $item ['title'],
|
||||
/*$2%s*/ $item ['ID'],
|
||||
/*$3%s*/ $this->row_actions( $actions ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* ************************************************************************
|
||||
* REQUIRED if displaying checkboxes or using bulk actions! The 'cb' column
|
||||
* is given special treatment when columns are processed.
|
||||
* It ALWAYS needs to
|
||||
* have it's own method.
|
||||
*
|
||||
* @see WP_List_Table::::single_row_columns()
|
||||
* @param array $item
|
||||
* A singular item (one full row's worth of data)
|
||||
* @return string Text to be placed inside the column <td> (movie title only)
|
||||
* ************************************************************************
|
||||
*/
|
||||
function column_cb( $item ) {
|
||||
return sprintf( '<input type="checkbox" name="%1$s[]" value="%2$s" />',
|
||||
/*$1%s*/ $this->_args ['singular'], // Let's simply repurpose the table's singular label ("movie")
|
||||
/* $2%s */
|
||||
$item ['ID'] ); // The value of the checkbox should be the record's id
|
||||
}
|
||||
|
||||
/**
|
||||
* ************************************************************************
|
||||
* REQUIRED! This method dictates the table's columns and titles.
|
||||
* This should
|
||||
* return an array where the key is the column slug (and class) and the value
|
||||
* is the column's title text. If you need a checkbox for bulk actions, refer
|
||||
* to the $columns array below.
|
||||
*
|
||||
* The 'cb' column is treated differently than the rest. If including a checkbox
|
||||
* column in your table you must create a column_cb() method. If you don't need
|
||||
* bulk actions or checkboxes, simply leave the 'cb' entry out of your array.
|
||||
*
|
||||
* @see WP_List_Table::::single_row_columns()
|
||||
* @return array An associative array containing column information: 'slugs'=>'Visible Titles'
|
||||
* ************************************************************************
|
||||
*/
|
||||
function get_columns() {
|
||||
$columns = array(
|
||||
'cb' => '<input type="checkbox" />', // Render a checkbox instead of text
|
||||
'title' => _x( 'Subject', 'What is the subject of this message?', 'post-smtp' ),
|
||||
'sent_to' => __( 'Sent To', 'post-smtp' ),
|
||||
'status' => __( 'Status', 'post-smtp' ),
|
||||
'solution' => __( 'Solution', 'post-smtp' ),
|
||||
'date' => _x( 'Delivery Time', 'When was this email sent?', 'post-smtp' ),
|
||||
);
|
||||
return $columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* ************************************************************************
|
||||
* Optional.
|
||||
* If you want one or more columns to be sortable (ASC/DESC toggle),
|
||||
* you will need to register it here. This should return an array where the
|
||||
* key is the column that needs to be sortable, and the value is db column to
|
||||
* sort by. Often, the key and value will be the same, but this is not always
|
||||
* the case (as the value is a column name from the database, not the list table).
|
||||
*
|
||||
* This method merely defines which columns should be sortable and makes them
|
||||
* clickable - it does not handle the actual sorting. You still need to detect
|
||||
* the ORDERBY and ORDER querystring variables within prepare_items() and sort
|
||||
* your data accordingly (usually by modifying your query).
|
||||
*
|
||||
* @return array An associative array containing all the columns that should be sortable: 'slugs'=>array('data_values',bool)
|
||||
* ************************************************************************
|
||||
*/
|
||||
function get_sortable_columns() {
|
||||
return array();
|
||||
$sortable_columns = array(
|
||||
'title' => array(
|
||||
'title',
|
||||
false,
|
||||
), // true means it's already sorted
|
||||
'status' => array(
|
||||
'status',
|
||||
false,
|
||||
),
|
||||
'date' => array(
|
||||
'date',
|
||||
false,
|
||||
),
|
||||
);
|
||||
return $sortable_columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* ************************************************************************
|
||||
* Optional.
|
||||
* If you need to include bulk actions in your list table, this is
|
||||
* the place to define them. Bulk actions are an associative array in the format
|
||||
* 'slug'=>'Visible Title'
|
||||
*
|
||||
* If this method returns an empty value, no bulk action will be rendered. If
|
||||
* you specify any bulk actions, the bulk actions box will be rendered with
|
||||
* the table automatically on display().
|
||||
*
|
||||
* Also note that list tables are not automatically wrapped in <form> elements,
|
||||
* so you will need to create those manually in order for bulk actions to function.
|
||||
*
|
||||
* @return array An associative array containing all the bulk actions: 'slugs'=>'Visible Titles'
|
||||
* ************************************************************************
|
||||
*/
|
||||
function get_bulk_actions() {
|
||||
$actions = array(
|
||||
'bulk_delete' => _x( 'Delete', 'Delete an item from the email log', 'post-smtp' ),
|
||||
);
|
||||
return $actions;
|
||||
}
|
||||
|
||||
/**
|
||||
* ************************************************************************
|
||||
* Optional.
|
||||
* You can handle your bulk actions anywhere or anyhow you prefer.
|
||||
* For this example package, we will handle it in the class to keep things
|
||||
* clean and organized.
|
||||
*
|
||||
* @see $this->prepare_items() ************************************************************************
|
||||
*/
|
||||
function process_bulk_action() {
|
||||
}
|
||||
|
||||
/**
|
||||
* ************************************************************************
|
||||
* REQUIRED! This is where you prepare your data for display.
|
||||
* This method will
|
||||
* usually be used to query the database, sort and filter the data, and generally
|
||||
* get it ready to be displayed. At a minimum, we should set $this->items and
|
||||
* $this->set_pagination_args(), although the following properties and methods
|
||||
* are frequently interacted with here...
|
||||
*
|
||||
* @global WPDB $wpdb
|
||||
* @uses $this->_column_headers
|
||||
* @uses $this->items
|
||||
* @uses $this->get_columns()
|
||||
* @uses $this->get_sortable_columns()
|
||||
* @uses $this->get_pagenum()
|
||||
* @uses $this->set_pagination_args()
|
||||
* ************************************************************************
|
||||
*/
|
||||
function prepare_items() {
|
||||
|
||||
if ( ! current_user_can( Postman::MANAGE_POSTMAN_CAPABILITY_LOGS ) ) {
|
||||
wp_die( sprintf( 'You need to add to this user the %s capability. You can try disable and enable the plugin or you can do it with a plugin like `user role editor`.', Postman::MANAGE_POSTMAN_CAPABILITY_LOGS ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* First, lets decide how many records per page to show
|
||||
*/
|
||||
$per_page = isset( $_GET['postman_page_records'] ) ? absint( $_GET['postman_page_records'] ) : 10;
|
||||
|
||||
/**
|
||||
* REQUIRED.
|
||||
* Now we need to define our column headers. This includes a complete
|
||||
* array of columns to be displayed (slugs & titles), a list of columns
|
||||
* to keep hidden, and a list of columns that are sortable. Each of these
|
||||
* can be defined in another method (as we've done here) before being
|
||||
* used to build the value for our _column_headers property.
|
||||
*/
|
||||
$columns = $this->get_columns();
|
||||
$hidden = array();
|
||||
$sortable = $this->get_sortable_columns();
|
||||
|
||||
/**
|
||||
* REQUIRED.
|
||||
* Finally, we build an array to be used by the class for column
|
||||
* headers. The $this->_column_headers property takes an array which contains
|
||||
* 3 other arrays. One for all columns, one for hidden columns, and one
|
||||
* for sortable columns.
|
||||
*/
|
||||
$this->_column_headers = array(
|
||||
$columns,
|
||||
$hidden,
|
||||
$sortable,
|
||||
);
|
||||
|
||||
/**
|
||||
* Optional.
|
||||
* You can handle your bulk actions however you see fit. In this
|
||||
* case, we'll handle them within our package just to keep things clean.
|
||||
*/
|
||||
$this->process_bulk_action();
|
||||
|
||||
/**
|
||||
* Instead of querying a database, we're going to fetch the example data
|
||||
* property we created for use in this plugin.
|
||||
* This makes this example
|
||||
* package slightly different than one you might build on your own. In
|
||||
* this example, we'll be using array manipulation to sort and paginate
|
||||
* our data. In a real-world implementation, you will probably want to
|
||||
* use sort and pagination data to build a custom query instead, as you'll
|
||||
* be able to use your precisely-queried data immediately.
|
||||
*/
|
||||
$data = array();
|
||||
|
||||
$args = array(
|
||||
'posts_per_page' => -1,
|
||||
'orderby' => 'date',
|
||||
'order' => 'DESC',
|
||||
'post_type' => PostmanEmailLogPostType::POSTMAN_CUSTOM_POST_TYPE_SLUG,
|
||||
'post_status' => 'private',
|
||||
'suppress_filters' => true,
|
||||
);
|
||||
|
||||
if ( isset( $_GET['from_date'] ) && ! empty( $_GET['from_date'] ) ) {
|
||||
$from_date = sanitize_text_field( $_GET['from_date'] );
|
||||
|
||||
$args['date_query']['after'] = $from_date;
|
||||
$args['date_query']['column'] = 'post_date';
|
||||
$args['date_query']['inclusive'] = false;
|
||||
}
|
||||
|
||||
if ( isset( $_GET['to_date'] ) && ! empty( $_GET['to_date'] ) ) {
|
||||
$to_date = sanitize_text_field( $_GET['to_date'] );
|
||||
|
||||
$args['date_query']['before'] = $to_date;
|
||||
$args['date_query']['column'] = 'post_date';
|
||||
$args['date_query']['inclusive'] = true;
|
||||
}
|
||||
|
||||
if ( ! empty( $_GET['search'] ) ) {
|
||||
|
||||
if ( isset( $args['date_query'] ) ) {
|
||||
unset( $args['date_query'] ); }
|
||||
|
||||
$args['s'] = sanitize_text_field( $_GET['search'] );
|
||||
}
|
||||
|
||||
if ( isset( $_GET['postman_trash_all'] ) ) {
|
||||
$args['posts_per_page'] = -1;
|
||||
}
|
||||
$posts = new WP_query( $args );
|
||||
|
||||
$date_format = get_option( 'date_format' );
|
||||
$time_format = get_option( 'time_format' );
|
||||
|
||||
foreach ( $posts->posts as $post ) {
|
||||
$date = $post->post_date;
|
||||
$humanTime = human_time_diff( strtotime( $post->post_date_gmt ) );
|
||||
// if this PHP system support humanTime, than use it
|
||||
if ( ! empty( $humanTime ) ) {
|
||||
/* Translators: where %s indicates the relative time from now */
|
||||
$date = sprintf( _x( '%s ago', 'A relative time as in "five days ago"', 'post-smtp' ), $humanTime );
|
||||
}
|
||||
$meta_values = PostmanLogFields::get_instance()->get( $post->ID );
|
||||
$sent_to = array_map( 'esc_html', explode( ',' , $meta_values ['to_header'] [0] ) );
|
||||
$solution_meta = $meta_values ['solution'] [0];
|
||||
|
||||
if ( empty( $solution_meta ) && empty( $post->post_excerpt ) ) {
|
||||
$solution = 'No need - Mail sent';
|
||||
} else {
|
||||
$solution = $solution_meta;
|
||||
}
|
||||
|
||||
$flattenedPost = array(
|
||||
// the post title must be escaped as they are displayed in the HTML output
|
||||
'sent_to' => implode( ', ', $sent_to ),
|
||||
'title' => esc_html( $post->post_title ),
|
||||
'solution' => $solution,
|
||||
// the post status must be escaped as they are displayed in the HTML output
|
||||
'status' => ($post->post_excerpt != null ? esc_html( $post->post_excerpt ) : __( 'Sent', 'post-smtp' )),
|
||||
'date' => date( "$date_format $time_format", strtotime( $post->post_date ) ),
|
||||
'ID' => $post->ID,
|
||||
);
|
||||
array_push( $data, $flattenedPost );
|
||||
}
|
||||
|
||||
/**
|
||||
* *********************************************************************
|
||||
* ---------------------------------------------------------------------
|
||||
* vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
|
||||
*
|
||||
* In a real-world situation, this is where you would place your query.
|
||||
*
|
||||
* For information on making queries in WordPress, see this Codex entry:
|
||||
* http://codex.wordpress.org/Class_Reference/wpdb
|
||||
*
|
||||
* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
* ---------------------------------------------------------------------
|
||||
* ********************************************************************
|
||||
*/
|
||||
|
||||
/**
|
||||
* REQUIRED for pagination.
|
||||
* Let's figure out what page the user is currently
|
||||
* looking at. We'll need this later, so you should always include it in
|
||||
* your own package classes.
|
||||
*/
|
||||
$current_page = $this->get_pagenum();
|
||||
|
||||
/**
|
||||
* REQUIRED for pagination.
|
||||
* Let's check how many items are in our data array.
|
||||
* In real-world use, this would be the total number of items in your database,
|
||||
* without filtering. We'll need this later, so you should always include it
|
||||
* in your own package classes.
|
||||
*/
|
||||
$total_items = count( $data );
|
||||
|
||||
/**
|
||||
* The WP_List_Table class does not handle pagination for us, so we need
|
||||
* to ensure that the data is trimmed to only the current page.
|
||||
* We can use
|
||||
* array_slice() to
|
||||
*/
|
||||
$data = array_slice( $data, (($current_page - 1) * $per_page), $per_page );
|
||||
|
||||
/**
|
||||
* REQUIRED.
|
||||
* Now we can add our *sorted* data to the items property, where
|
||||
* it can be used by the rest of the class.
|
||||
*/
|
||||
$this->items = $data;
|
||||
|
||||
/**
|
||||
* REQUIRED.
|
||||
* We also have to register our pagination options & calculations.
|
||||
*/
|
||||
$this->set_pagination_args( array(
|
||||
'total_items' => $total_items, // WE have to calculate the total number of items
|
||||
'per_page' => $per_page, // WE have to determine how many items to show on a page
|
||||
'total_pages' => ceil( $total_items / $per_page ),
|
||||
) ); // WE have to calculate the total number of pages
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,369 @@
|
||||
<?php
|
||||
|
||||
if( !class_exists( 'PostmanEmailQueryLog' ) ):
|
||||
class PostmanEmailQueryLog {
|
||||
|
||||
private $db = '';
|
||||
public $table = 'post_smtp_logs';
|
||||
public $meta_table = 'post_smtp_logmeta';
|
||||
private $query = '';
|
||||
private $columns = array();
|
||||
|
||||
|
||||
/**
|
||||
* The Construct PostmanEmailQueryLog
|
||||
*
|
||||
* @since 2.5.0
|
||||
* @version 1.0.0
|
||||
*/
|
||||
public function __construct() {
|
||||
|
||||
global $wpdb;
|
||||
$this->db = $wpdb;
|
||||
$this->table = $this->db->prefix . $this->table;
|
||||
$this->meta_table = $this->db->prefix . $this->meta_table;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get Logs
|
||||
*
|
||||
* @param $args String
|
||||
* @since 2.5.0
|
||||
* @version 1.0.0
|
||||
*/
|
||||
public function get_logs( $args = array() ) {
|
||||
|
||||
/**
|
||||
* Filter the query arguments
|
||||
*
|
||||
* @param $args Array
|
||||
* @since 2.5.0
|
||||
* @version 1.0.0
|
||||
*/
|
||||
$args = apply_filters( 'post_smtp_get_logs_args', $args );
|
||||
|
||||
$clause_for_date = empty( $args['search'] ) ? $this->query .= " WHERE" : $this->query .= " AND";
|
||||
|
||||
$args['search_by'] = array(
|
||||
'original_subject',
|
||||
'success',
|
||||
'to_header'
|
||||
);
|
||||
|
||||
if( !isset( $args['columns'] ) ) {
|
||||
|
||||
$this->columns = array(
|
||||
'id',
|
||||
'original_subject',
|
||||
'to_header',
|
||||
'success',
|
||||
'time',
|
||||
'original_to'
|
||||
);
|
||||
|
||||
}
|
||||
else {
|
||||
|
||||
$this->columns = $args['columns'];
|
||||
|
||||
}
|
||||
|
||||
$this->columns = array_map( function( $column ) {
|
||||
return "pl.`{$column}`";
|
||||
}, $this->columns );
|
||||
|
||||
$this->columns = implode( ',', $this->columns );
|
||||
|
||||
/**
|
||||
* Filter the query columns
|
||||
*
|
||||
* @param $query String
|
||||
* @param $args Array
|
||||
* @since 2.5.0
|
||||
* @version 1.0.0
|
||||
*/
|
||||
$this->columns = apply_filters( 'post_smtp_get_logs_query_cols', $this->columns, $args );
|
||||
|
||||
$this->query = $this->db->prepare(
|
||||
"SELECT {$this->columns} FROM %i AS pl",
|
||||
$this->table
|
||||
);
|
||||
|
||||
/**
|
||||
* Filter the query after the table name
|
||||
*
|
||||
* @param $query String
|
||||
* @param $args Array
|
||||
* @since 2.5.0
|
||||
* @version 1.0.0
|
||||
*/
|
||||
$this->query = apply_filters( 'post_smtp_get_logs_query_after_table', $this->query, $args );
|
||||
|
||||
//Search
|
||||
if( !empty( $args['search'] ) ) {
|
||||
|
||||
$this->query .= " WHERE";
|
||||
$counter = 1;
|
||||
|
||||
foreach( $args['search_by'] as $key ) {
|
||||
|
||||
$this->query .= $this->db->prepare(
|
||||
" {$key} LIKE %s",
|
||||
'%' . $this->db->esc_like( $args['search'] ) . '%'
|
||||
);
|
||||
$this->query .= $counter != count( $args['search_by'] ) ? ' OR' : '';
|
||||
$counter++;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//Date Filter :)
|
||||
if( isset( $args['from'] ) && !empty( $args['from'] ) ) {
|
||||
|
||||
$this->query .= $this->db->prepare(
|
||||
" {$clause_for_date} pl.`time` >= %d",
|
||||
$args['from']
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
if( isset( $args['to'] ) && !empty( $args['to'] ) ) {
|
||||
|
||||
$clause_for_date = strpos( $this->query, 'WHERE' ) !== FALSE ? ' AND' : ' WHERE';
|
||||
|
||||
$this->query .= $this->db->prepare(
|
||||
" {$clause_for_date} pl.`time` <= %d",
|
||||
$args['to']
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
// Status Filter
|
||||
$clause_for_status = '';
|
||||
if( isset( $args['status'] ) && !empty( $args['status'] ) ) {
|
||||
|
||||
$clause_for_status = strpos( $this->query, 'WHERE' ) !== FALSE ? ' AND' : ' WHERE';
|
||||
|
||||
if( $args['status'] == 'success' ) {
|
||||
// Include both regular success (success = 1) and fallback success entries
|
||||
$this->query .= "{$clause_for_status} (`success` = 1 OR `success` = 'Sent ( ** Fallback ** )' OR `success` LIKE '( ** Fallback ** )%') ";
|
||||
}
|
||||
elseif ( $args['status'] == 'failed' ) {
|
||||
// Exclude successful entries (both regular and fallback)
|
||||
$this->query .= "{$clause_for_status} (`success` != 1 AND `success` != 'Sent ( ** Fallback ** )' AND `success` NOT LIKE '( ** Fallback ** )%') ";
|
||||
}
|
||||
else {
|
||||
|
||||
$this->query .= '';
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if( isset( $args['site_id'] ) && $args['site_id'] != -1 ) {
|
||||
|
||||
$clause_for_site = ( empty( $args['search'] ) && strpos( $this->query, 'WHERE' ) === false ) ? " WHERE" : " AND";
|
||||
|
||||
$this->query .= " {$clause_for_site} lm.meta_value = '{$args['site_id']}'";
|
||||
|
||||
}
|
||||
|
||||
//Order By
|
||||
if( !empty( $args['order'] ) && !empty( $args['order_by'] ) ) {
|
||||
|
||||
$orderby_sql = sanitize_sql_orderby( "`{$args['order_by']}` {$args['order']}" );
|
||||
|
||||
//If no alias added, add one
|
||||
if( !strpos( $args['order_by'], '.' ) ) {
|
||||
|
||||
$orderby_sql = "pl.{$orderby_sql}";
|
||||
|
||||
}
|
||||
|
||||
$this->query .= " ORDER BY {$orderby_sql}";
|
||||
|
||||
}
|
||||
|
||||
//Lets say from 0 to 25
|
||||
if( isset( $args['start'] ) && isset( $args['end'] ) ) {
|
||||
|
||||
$this->query .= $this->db->prepare(
|
||||
" LIMIT %d, %d",
|
||||
$args['start'],
|
||||
$args['end']
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
return $this->db->get_results( $this->query );
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get Filtered Rows Count
|
||||
* Total records, after filtering (i.e. the total number of records after filtering has been applied - not just the number of records being returned for this page of data).
|
||||
*
|
||||
* @since 2.5.0
|
||||
* @version 1.0.0
|
||||
*/
|
||||
public function get_filtered_rows_count() {
|
||||
|
||||
$query = str_replace( $this->columns, 'COUNT(*) as count', $this->query );
|
||||
|
||||
//Remove LIMIT clouse to use COUNT clouse properly
|
||||
$query = substr( $query, 0, strpos( $query, "LIMIT" ) );
|
||||
|
||||
return $this->db->get_results( $query );
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets Total Rows Count
|
||||
* Total records, before filtering (i.e. the total number of records in the database)
|
||||
*
|
||||
* @since 2.5.0
|
||||
* @version 1.0.0
|
||||
*/
|
||||
public function get_total_row_count() {
|
||||
|
||||
return $this->db->get_results(
|
||||
$this->db->prepare(
|
||||
"SELECT COUNT(*) as count FROM %i;",
|
||||
$this->table
|
||||
)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get Last Log ID
|
||||
*
|
||||
* @since 2.5.0
|
||||
* @version 1.0.0
|
||||
*/
|
||||
public function get_last_log_id() {
|
||||
|
||||
$result = $this->db->get_results(
|
||||
$this->db->prepare(
|
||||
"SELECT id FROM %i ORDER BY id DESC LIMIT 1;",
|
||||
$this->table
|
||||
)
|
||||
);
|
||||
|
||||
return empty( $result ) ? false : $result[0]->id;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Delete Logs
|
||||
*
|
||||
* @param $ids Array
|
||||
* @since 2.5.0
|
||||
* @version 1.0.0
|
||||
*/
|
||||
public function delete_logs( $ids = array() ) {
|
||||
|
||||
$ids = implode( ',', $ids );
|
||||
$ids_log = $ids == -1 ? '' : "WHERE id IN ({$ids});";
|
||||
$ids_meta_logs = $ids == -1 ? '' : "WHERE log_id IN ({$ids});";
|
||||
|
||||
$this->db->query(
|
||||
$this->db->prepare(
|
||||
"DELETE FROM %i {$ids_meta_logs}",
|
||||
$this->meta_table
|
||||
)
|
||||
);
|
||||
|
||||
return $this->db->query(
|
||||
$this->db->prepare(
|
||||
"DELETE FROM %i {$ids_log}",
|
||||
$this->table
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get All Logs
|
||||
*
|
||||
* @param $ids Array
|
||||
* @since 2.5.0
|
||||
* @version 1.0.0
|
||||
*/
|
||||
public function get_all_logs( $ids = array() ) {
|
||||
|
||||
$ids = implode( ',', $ids );
|
||||
$ids = $ids == -1 ? '' : "WHERE id IN ({$ids});";
|
||||
|
||||
return $this->db->get_results(
|
||||
$this->db->prepare(
|
||||
"SELECT * FROM %i {$ids}",
|
||||
$this->table
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get Log
|
||||
*
|
||||
* @param $id Int
|
||||
* @param $columns Array
|
||||
* @since 2.5.0
|
||||
* @version 1.0.0
|
||||
*/
|
||||
public function get_log( $id, $columns = array() ) {
|
||||
|
||||
$allowed_columns = array(
|
||||
'id',
|
||||
'solution',
|
||||
'success',
|
||||
'from_header',
|
||||
'to_header',
|
||||
'cc_header',
|
||||
'bcc_header',
|
||||
'reply_to_header',
|
||||
'transport_uri',
|
||||
'original_to',
|
||||
'original_subject',
|
||||
'original_message',
|
||||
'original_headers',
|
||||
'session_transcript',
|
||||
'time',
|
||||
);
|
||||
|
||||
// Validate and sanitize columns.
|
||||
if ( empty( $columns ) || ! is_array( $columns ) ) {
|
||||
$columns_sql = '*';
|
||||
} else {
|
||||
$safe_columns = array_intersect( $columns, $allowed_columns );
|
||||
$columns_sql = ! empty( $safe_columns ) ? implode( ', ', array_map( 'esc_sql', $safe_columns ) ) : '*';
|
||||
}
|
||||
|
||||
// Sanitize table name.
|
||||
$table = esc_sql( $this->table );
|
||||
|
||||
// Prepare and execute the query securely.
|
||||
$query = $this->db->prepare(
|
||||
"SELECT {$columns_sql} FROM %i WHERE id = %d",
|
||||
$table,
|
||||
$id
|
||||
);
|
||||
|
||||
return $this->db->get_row( $query, ARRAY_A );
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
endif;
|
||||
Reference in New Issue
Block a user