first commit

This commit is contained in:
2024-07-15 11:28:08 +02:00
commit f52d538ea5
21891 changed files with 6161164 additions and 0 deletions

View File

@@ -0,0 +1,144 @@
/* General Purpose Classes */
.tnp-legend {
font-family: "Source Sans Pro", sans-serif;
color: #fff;
text-transform: uppercase;
padding: 0px 15px;
display: inline-block;
vertical-align: middle;
}
/* Statistics General Infobox */
.tnp-statistics-general-icon {
display: inline-block;
background-color: #2980B9;
padding: 20px 18px 14px 18px;
}
.tnp-statistics-general-box {
background-color: #2980B9;
display: inline-block;
padding: 10px;
margin: 10px 0px 10px 0px;
}
#tnp-heading .tnp-statistics-general-box p {
color: #fff;
line-height: 25px;
}
.tnp-statistics-general-title {
font-family: "Source Sans Pro", sans-serif;
letter-spacing: 0.05rem;
background-color: #2980B9;
color: #fff;
margin: 15px 0px;
padding: 9px;
border: 0;
font-size: 14px;
text-transform: uppercase;
}
.tnp-statistics-info-box {
background-color: #3a5168;
}
.tnp-statistics-info-box .button, .tnp-statistics-info-box .button-secondary {
vertical-align: middle;
}
/* Subscribers Reached Box */
.tnp-row-pie-charts {
margin: 20px 0px;
}
.tnp-row-pie-charts canvas[style] {
width: 100% !important;
height: 100% !important;
}
.tnp-widget .tnp-data {
text-align: center;
padding: 15px 0;
}
.tnp-widget .tnp-data .tnp-data-title{
font-size: 9px;
font-weight: 700;
text-transform: uppercase;
font-family: "Source Sans Pro";
}
.tnp-widget .tnp-data .tnp-data-value{
font-size: 15px;
color: #415b76;
}
/* Map Box */
#tnp-map-chart {
width: 450px;
height: 320px;
margin: 0px auto;
position: relative;
overflow: hidden;
}
#tnp-map-chart .jqvmap-zoomin, #tnp-map-chart .jqvmap-zoomout {
color: #fff;
padding: 0px;
}
.tnp-map-legend, .tnp-gender-legend, .tnp-events-legend {
font-family: "Source Sans Pro", sans-serif;
color: #2C3E50;
text-transform: uppercase;
text-align: center;
margin-bottom: 40px !important;
}
/* Subscribers Gender Box */
#tnp-gender-chart {
width: 90%;
margin: 0 auto;
}
/* Events Over Time */
#tnp-events-chart {
width: 80%;
margin: 0 auto;
height: 300px;
}
/* Retarget Table Layout */
.tnp-retarget .tnp-retarget-table {
background-color: #34495E;
border: none;
}
.tnp-retarget .tnp-retarget-table th {
color: #fff;
border: none;
}
#tnp-body.tnp-statistics .tnp-widget {
min-height: 500px;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 495 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

View File

@@ -0,0 +1,302 @@
<?php
/* @var $wpdb wpdb */
if (!defined('ABSPATH'))
exit;
require_once NEWSLETTER_INCLUDES_DIR . '/controls.php';
$module = NewsletterStatistics::instance();
$controls = new NewsletterControls();
wp_enqueue_script('tnp-chart');
if ($controls->is_action('country')) {
$module->country();
$controls->messages = $module->country_result;
}
if ($controls->is_action('import')) {
$wpdb->query("insert ignore into " . $wpdb->prefix . "newsletter_sent (user_id, email_id, time) select user_id, email_id, UNIX_TIMESTAMP(created) from " . NEWSLETTER_STATS_TABLE);
$controls->messages = 'Done!';
}
$types = $wpdb->get_results("select distinct type from " . NEWSLETTER_EMAILS_TABLE);
$type_options = array();
foreach ($types as $type) {
if ($type->type == 'followup')
continue;
if ($type->type == 'message') {
$type_options[$type->type] = 'Standard Newsletter';
} else if ($type->type == 'feed') {
$type_options[$type->type] = 'Feed by Mail';
} else if (strpos($type->type, 'automated') === 0) {
list($a, $id) = explode('_', $type->type);
$type_options[$type->type] = 'Automated Channel ' . $id;
} else {
$type_options[$type->type] = $type->type;
}
}
if (empty($controls->data['type'])) {
$emails = $wpdb->get_results("select send_on, id, subject, total, status, type, track, sent, subject from " . NEWSLETTER_EMAILS_TABLE . " where status='sent' order by send_on desc limit 20");
} else {
$emails = $wpdb->get_results($wpdb->prepare("select send_on, id, subject, total, type from " . NEWSLETTER_EMAILS_TABLE . " where status='sent' and type=%s order by send_on desc limit 20", $controls->data['type']));
}
$overview_labels = array();
$overview_titles = array();
$overview_open_rate = array();
$overview_click_rate = array();
$total_sent = 0;
$open_count_total = 0;
$click_count_total = 0;
foreach ($emails as $email) {
$entry = array();
// Skip newsletters which has no sent records
$total = $module->get_total_count($email);
if (empty($total)) {
continue;
}
$total_sent += $total;
//$entry[0] = $email->subject . ' [' . date('Y-m-d', $email->send_on) . ', ' . $email->type . ']';
$entry[0] = date('Y-m-d', $email->send_on);
$open_count = $module->get_open_count($email);
$open_count_total += $open_count;
$entry[1] = $open_count / $total * 100;
$entry[1] = round($entry[1], 2);
$entry[2] = $email->subject; // . ' (' . percent($open_count, $email->sent) . ')';
$click_count = $module->get_click_count($email);
$click_count_total += $click_count;
$entry[3] = $click_count / $total * 100;
$entry[3] = round($entry[3], 2);
$overview_labels[] = strftime('%a, %e %b', $email->send_on);
$overview_open_rate[] = $entry[1];
$overview_click_rate[] = $entry[3];
$overview_titles[] = $entry[2];
}
$overview_labels = array_reverse($overview_labels);
$overview_open_rate = array_reverse($overview_open_rate);
$overview_click_rate = array_reverse($overview_click_rate);
?>
<div class="wrap" id="tnp-wrap">
<?php include NEWSLETTER_DIR . '/tnp-header.php' ?>
<div id="tnp-heading">
<h2><?php _e('Global Newsletter Statistics', 'newsletter') ?></h2>
</div>
<div id="tnp-body" class="tnp-statistics">
<form method="post" action="">
<?php $controls->init(); ?>
<?php if (empty($emails)) { ?>
<img src="https://cdn.thenewsletterplugin.com/tnp-reports-dummy-image.png" style="max-width: 100%">
<?php } else { ?>
<div class="row">
<div class="tnp-statistics-info-box">
<p class="tnp-legend">Select Newsletter category:</p>
<?php $controls->select('type', $type_options, 'All') ?>
<?php $controls->button('update', __('Update Charts', 'newsletter')) ?>
</div>
</div>
<br>
<div class="row">
<div class="col-md-6">
<div class="tnp-widget">
<h3>Overview (Last 20 Newsletters)</h3>
<div class="inside">
<p class="tnp-events-legend">Subscribers interactions distribution over time,<br>starting from the sending day.</p>
<div id="tnp-events-chart">
<canvas id="tnp-events-chart-canvas"></canvas>
</div>
<script type="text/javascript">
var events_data = {
labels: <?php echo json_encode($overview_labels) ?>,
datasets: [
{
label: "Open",
fill: false,
strokeColor: "#27AE60",
backgroundColor: "#27AE60",
borderColor: "#27AE60",
pointBorderColor: "#27AE60",
pointBackgroundColor: "#27AE60",
data: <?php echo json_encode($overview_open_rate) ?>
},
{
label: "Click",
fill: false,
strokeColor: "#C0392B",
backgroundColor: "#C0392B",
borderColor: "#C0392B",
pointBorderColor: "#C0392B",
pointBackgroundColor: "#C0392B",
data: <?php echo json_encode($overview_click_rate) ?>,
yAxisID: "y-axis-2"
}
]
};
var titles = <?php echo json_encode(array_reverse($overview_titles)) ?>;
jQuery(document).ready(function ($) {
ctxe = $('#tnp-events-chart-canvas').get(0).getContext("2d");
eventsLineChart = new Chart(ctxe, {type: 'line', data: events_data,
options: {
scales: {
xAxes: [{type: "category", "id": "x-axis-1", gridLines: {display: false}, ticks: {fontFamily: "Source Sans Pro"}}],
yAxes: [
{type: "linear", "id": "y-axis-1", gridLines: {display: false}, ticks: {fontColor: "#27AE60", fontFamily: "Source Sans Pro"}},
{type: "linear", "id": "y-axis-2", position: "right", gridLines: {display: false}, ticks: {fontColor: "#C0392B", fontFamily: "Source Sans Pro"}}
]
},
tooltips: {
callbacks: {
afterTitle: function (data) {
return titles[data[0].index];
},
label: function (tooltipItem, data) {
return data.datasets[0].label + ": " + data.datasets[0].data[tooltipItem.index] + "% " +
data.datasets[1].label + ": " + data.datasets[1].data[tooltipItem.index] + "%";
}
}
}
}
});
});
</script>
<div class="row">
<div class="col-md-4">
<div class="tnp-data">
<div class="tnp-data-title"><?php _e('Total Sent Messages', 'newsletter') ?></div>
<div class="tnp-data-value"><?php echo $total_sent; ?></div>
</div>
</div>
<div class="col-md-4">
<div class="tnp-data">
<div class="tnp-data-title"><?php _e('Opened Newsletters', 'newsletter') ?></div>
<div class="tnp-data-value"><?php echo $open_count_total; ?> (<?php echo $module->percent($open_count_total, $total_sent); ?>)</div>
</div>
</div>
<div class="col-md-4">
<div class="tnp-data">
<div class="tnp-data-title"><?php _e('Clicked Newsletters', 'newsletter') ?></div>
<div class="tnp-data-value"><?php echo $click_count_total; ?> (<?php echo $module->percent($click_count_total, $total_sent); ?>)</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- WORLD MAP -->
<div class="col-md-6">
<div class="tnp-widget">
<h3><?php _e('Countries', 'newsletter') ?></h3>
<div class="inside">
<?php
if (!has_action('newsletter_statistics_index_map')) {
?><a href="https://www.thenewsletterplugin.com/premium?utm_source=plugin&utm_medium=link&utm_content=worldmap&utm_campaign=newsletter-reports" target="_blank">
<img src="<?php echo plugins_url('newsletter') ?>/statistics/images/map.gif" style="width: 100%">
</a><?php
} else {
do_action('newsletter_statistics_index_map');
}
?>
</div>
</div>
</div>
</div>
<div class="row">
<!-- LAST NEWSLETTERS -->
<div class="col-md-12">
<div class="tnp-widget">
<h3><?php _e('Last newsletters', 'newsletter') ?> <a href="admin.php?page=newsletter_statistics_newsletters"><?php _e('Details', 'newsletter') ?></a></h3>
<div class="inside">
<?php
$emails = $wpdb->get_results($wpdb->prepare("select send_on, id, subject, total, status, type, track, sent, subject from " . NEWSLETTER_EMAILS_TABLE . " where status in ('sent', 'sending') and send_on<%d order by send_on desc limit 5", time()));
?>
<table class="widefat">
<thead>
<tr>
<th>Id</th>
<th><?php _e('Subject', 'newsletter') ?></th>
<th>Type</th>
<th><?php _e('Status', 'newsletter') ?></th>
<th>&nbsp;</th>
</tr>
</thead>
<tbody>
<?php foreach ($emails as &$email) { ?>
<tr>
<td><?php echo $email->id; ?></td>
<td><?php echo htmlspecialchars($email->subject); ?></td>
<td><?php echo $module->get_email_type_label($email); ?></td>
<td><?php echo $module->get_email_status_label($email); ?></td>
<td>
<a href="<?php echo NewsletterStatistics::instance()->get_statistics_url($email->id); ?>" class="button-primary">Statistics</a>
</td>
</tr>
<?php } ?>
</tbody>
</table>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="tnp-statistics-info-box">
<p class="tnp-legend">Check Statistics global<br>configurations.</p>
<a class="button-primary" href="admin.php?page=newsletter_statistics_settings"><?php _e('Settings') ?></a>
</div>
</div>
<div class="col-md-6">
</div>
</div>
<?php } ?>
</form>
</div>
<?php include NEWSLETTER_DIR . '/tnp-footer.php' ?>
</div>

View File

@@ -0,0 +1,79 @@
<?php
if (!defined('ABSPATH')) exit;
require_once NEWSLETTER_INCLUDES_DIR . '/controls.php';
$module = NewsletterStatistics::instance();
$controls = new NewsletterControls();
$emails = Newsletter::instance()->get_emails();
$types = $wpdb->get_results("select distinct type from " . NEWSLETTER_EMAILS_TABLE);
$type_options = array();
foreach ($types as $type) {
if ($type->type == 'followup')
continue;
if ($type->type == 'message') {
$type_options[$type->type] = 'Standard Newsletter';
} else if ($type->type == 'feed') {
$type_options[$type->type] = 'Feed by Mail';
} else if (strpos($type->type, 'automated') === 0) {
list($a, $id) = explode('_', $type->type);
$type_options[$type->type] = 'Automated Channel ' . $id;
} else {
$type_options[$type->type] = $type->type;
}
}
?>
<div class="wrap" id="tnp-wrap">
<?php include NEWSLETTER_DIR . '/tnp-header.php'; ?>
<div id="tnp-heading">
<h2><?php _e('Newsletters', 'newsletter') ?></h2>
</div>
<div id="tnp-body">
<form method="post" action="">
<?php $controls->init(); ?>
<table class="widefat">
<thead>
<tr>
<th>Id</th>
<th><?php _e('Subject', 'newsletter') ?></th>
<th>Type</th>
<th><?php _e('Status', 'newsletter') ?></th>
<th>&nbsp;</th>
<th>&nbsp;</th>
<th><?php _e('Tracking', 'newsletter') ?></th>
<th>&nbsp;</th>
</tr>
</thead>
<tbody>
<?php foreach ($emails as &$email) { ?>
<?php if ($email->type != 'message' && $email->type != 'feed') continue; ?>
<tr>
<td><?php echo $email->id; ?></td>
<td><?php echo esc_html($email->subject); ?></td>
<td><?php echo esc_html($module->get_email_type_label($email)) ?></td>
<td><?php echo esc_html($module->get_email_status_label($email)) ?></td>
<td><?php if ($email->status == 'sent' || $email->status == 'sending') echo $email->sent . ' ' . __('of', 'newsletter') . ' ' . $email->total; ?></td>
<td><?php if ($email->status == 'sent' || $email->status == 'sending') echo $module->format_date($email->send_on); ?></td>
<td><?php echo $email->track == 1 ? 'Yes' : 'No'; ?></td>
<td>
<a class="button-primary" href="<?php echo NewsletterStatistics::instance()->get_statistics_url($email->id); ?>">statistics</a>
</td>
</tr>
<?php } ?>
</tbody>
</table>
</form>
</div>
<?php include NEWSLETTER_DIR . '/tnp-footer.php'; ?>
</div>

View File

@@ -0,0 +1,77 @@
<?php
if (!defined('ABSPATH')) exit;
require_once NEWSLETTER_INCLUDES_DIR . '/controls.php';
$module = NewsletterStatistics::instance();
$controls = new NewsletterControls();
if (!$controls->is_action()) {
$controls->data = $module->options;
}
do_action('newsletter_statistics_settings_init', $controls);
if ($controls->is_action('save')) {
$module->save_options($controls->data);
$controls->add_message_saved();
}
?>
<div class="wrap" id="tnp-wrap">
<?php include NEWSLETTER_DIR . '/tnp-header.php'; ?>
<div id="tnp-heading">
<h2><?php _e('Statistics Settings', 'newsletter') ?></h2>
</div>
<div id="tnp-body">
<form method="post" action="">
<?php $controls->init(); ?>
<div id="tabs">
<ul>
<li><a href="#tab-configuration"><?php _e('Configuration', 'newsletter') ?></a></li>
<li><a href="#tab-countries"><?php _e('Countries', 'newsletter') ?></a></li>
</ul>
<div id="tab-configuration">
<table class="form-table">
<tr>
<th><?php _e('Secret key', 'newsletter') ?></th>
<td>
<?php $controls->text('key') ?>
<p class="description">
<?php _e('This auto-generated key is used to protect the click tracking. If you change it old tracking links to external domains won\'t be registered anymore.', 'newsletter-statistics') ?>
</p>
</td>
</tr>
</table>
<p>
<?php $controls->button_save() ?>
</p>
</div>
<div id="tab-countries">
<?php
if (!has_action('newsletter_statistics_settings_countries')) {
?>
<p>This panel contains information about country detection added by
<a href="https://www.thenewsletterplugin.com/plugins/newsletter/reports-module" target="_blank">Reports Extension</a>.</p>
<?php
} else {
do_action('newsletter_statistics_settings_countries', $controls);
}
?>
</div>
</div>
</form>
</div>
<?php include NEWSLETTER_DIR . '/tnp-footer.php' ?>
</div>

View File

@@ -0,0 +1,351 @@
<?php
defined('ABSPATH') || exit;
class NewsletterStatistics extends NewsletterModule {
static $instance;
const SENT_READ = 1;
const SENT_CLICK = 2;
/**
* @return NewsletterStatistics
*/
static function instance() {
if (self::$instance == null) {
self::$instance = new NewsletterStatistics();
}
return self::$instance;
}
function __construct() {
parent::__construct('statistics', '1.1.8');
add_action('wp_loaded', array($this, 'hook_wp_loaded'));
if (is_admin()) {
add_action('admin_enqueue_scripts', array($this, 'hook_admin_enqueue_scripts'));
}
}
function hook_admin_enqueue_scripts() {
if (isset($_GET['page']) && (strpos($_GET['page'], 'newsletter_statistics') === 0 || strpos($_GET['page'], 'newsletter_reports') === 0)) {
wp_enqueue_style('newsletter-admin-statistics', plugins_url('newsletter') . '/statistics/css/tnp-statistics.css', array('tnp-admin'), time());
}
}
/**
*
* @global wpdb $wpdb
*/
function hook_wp_loaded() {
global $wpdb;
// Newsletter Link Tracking
if (isset($_GET['nltr'])) {
// Patch for links with ;
$parts = explode(';', base64_decode($_GET['nltr']));
$email_id = (int) array_shift($parts);
$user_id = (int) array_shift($parts);
$signature = array_pop($parts);
$anchor = array_pop($parts); // No more used
// The remaining elements are the url splitted when it contains
$url = implode(';', $parts);
if (empty($user_id) || empty($url)) {
header("HTTP/1.0 404 Not Found");
die('Invalid data');
}
$parts = parse_url($url);
$verified = $signature == md5($email_id . ';' . $user_id . ';' . $url . ';' . $anchor . $this->options['key']);
if (!$verified) {
header("HTTP/1.0 404 Not Found");
die('Url not verified');
}
$user = Newsletter::instance()->get_user($user_id);
if (!$user) {
header("HTTP/1.0 404 Not Found");
die('Invalid subscriber');
}
// Test emails
if (empty($email_id)) {
header('Location: ' . esc_url_raw($url));
die();
}
$email = $this->get_email($email_id);
if (!$email) {
header("HTTP/1.0 404 Not Found");
die('Invalid newsletter');
}
setcookie('newsletter', $user->id . '-' . $user->token, time() + 60 * 60 * 24 * 365, '/');
$is_action = strpos($url, '?na=');
$ip = $this->get_remote_ip();
$ip = $this->process_ip($ip);
if (!$is_action) {
$this->add_click($url, $user_id, $email_id, $ip);
$this->update_open_value(self::SENT_CLICK, $user_id, $email_id, $ip);
} else {
// Track an action as an email read and not a click
$this->update_open_value(self::SENT_READ, $user_id, $email_id, $ip);
}
$this->update_user_ip($user, $ip);
$this->update_user_last_activity($user);
header('Location: ' . apply_filters('newsletter_redirect_url', $url, $email, $user));
die();
}
// Newsletter Open Traking Image
if (isset($_GET['noti'])) {
$this->logger->debug('Open tracking: ' . $_GET['noti']);
list($email_id, $user_id, $signature) = explode(';', base64_decode($_GET['noti']), 3);
$email = $this->get_email($email_id);
if (!$email) {
$this->logger->error('Open tracking request for unexistant email');
die();
}
$user = $this->get_user($user_id);
if (!$user) {
$this->logger->error('Open tracking request for unexistant subscriber');
die();
}
if ($email->token) {
$this->logger->debug('Signature: ' . $signature);
$s = md5($email_id . $user_id . $email->token);
if ($s != $signature) {
$this->logger->error('Open tracking request with wrong signature. Email token: ' . $email->token);
die();
}
} else {
$this->logger->info('Email with no token hence not signature to check');
}
$ip = $this->get_remote_ip();
$ip = $this->process_ip($ip);
$this->add_click('', $user_id, $email_id, $ip);
$this->update_open_value(self::SENT_READ, $user_id, $email_id, $ip);
$this->update_user_last_activity($user);
header('Content-Type: image/gif', true);
echo base64_decode('_R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7');
die();
}
}
function upgrade() {
global $wpdb, $charset_collate;
parent::upgrade();
$sql = "CREATE TABLE `" . $wpdb->prefix . "newsletter_stats` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`url` varchar(255) NOT NULL DEFAULT '',
`user_id` int(11) NOT NULL DEFAULT '0',
`email_id` varchar(10) NOT NULL DEFAULT '0',
`link_id` int(11) NOT NULL DEFAULT '0',
`ip` varchar(20) NOT NULL DEFAULT '',
`country` varchar(4) NOT NULL DEFAULT '',
PRIMARY KEY (`id`),
KEY `email_id` (`email_id`),
KEY `user_id` (`user_id`)
) $charset_collate;";
dbDelta($sql);
if (empty($this->options['key'])) {
$this->options['key'] = md5($_SERVER['REMOTE_ADDR'] . rand(100000, 999999) . time());
$this->save_options($this->options);
}
}
function admin_menu() {
$this->add_admin_page('index', 'Statistics');
$this->add_admin_page('view', 'Statistics');
$this->add_admin_page('newsletters', 'Statistics');
$this->add_admin_page('settings', 'Statistics');
$this->add_admin_page('view_retarget', 'Statistics');
$this->add_admin_page('view_urls', 'Statistics');
$this->add_admin_page('view_users', 'Statistics');
}
function relink($text, $email_id, $user_id, $email_token = '') {
$this->relink_email_id = $email_id;
$this->relink_user_id = $user_id;
$this->relink_email_token = $email_token;
$this->logger->debug('Relink with token: ' . $email_token);
$text = preg_replace_callback('/(<[aA][^>]+href[\s]*=[\s]*["\'])([^>"\']+)(["\'][^>]*>)(.*?)(<\/[Aa]>)/is', array($this, 'relink_callback'), $text);
$signature = md5($email_id . $user_id . $email_token);
$text = str_replace('</body>', '<img width="1" height="1" alt="" src="' . home_url('/') . '?noti=' . urlencode(base64_encode($email_id . ';' . $user_id . ';' . $signature)) . '"/></body>', $text);
return $text;
}
function relink_callback($matches) {
$href = trim(str_replace('&amp;', '&', $matches[2]));
// Do not replace the tracking or subscription/unsubscription links.
//if (strpos($href, '/newsletter/') !== false) {
// return $matches[0];
//}
// Do not replace URL which are tags (special case for ElasticEmail)
if (strpos($href, '{') === 0) {
return $matches[0];
}
// if (strpos($href, '?na=') !== false) {
// return $matches[0];
// }
// Do not relink anchors
if (substr($href, 0, 1) == '#') {
return $matches[0];
}
// Do not relink mailto:
if (substr($href, 0, 7) == 'mailto:') {
return $matches[0];
}
// This is the link text which is added to the tracking data
$anchor = '';
// if ($this->options['anchor'] == 1) {
// $anchor = trim(str_replace(';', ' ', $matches[4]));
// // Keep images but not other tags
// $anchor = strip_tags($anchor, '<img>');
//
// // Truncate if needed to avoid to much long URLs
// if (stripos($anchor, '<img') === false && strlen($anchor) > 100) {
// $anchor = substr($anchor, 0, 100);
// }
// }
$r = $this->relink_email_id . ';' . $this->relink_user_id . ';' . $href . ';' . $anchor;
$r = $r . ';' . md5($r . $this->options['key']);
$r = base64_encode($r);
$r = urlencode($r);
$url = home_url('/') . '?nltr=' . $r;
return $matches[1] . $url . $matches[3] . $matches[4] . $matches[5];
}
function get_statistics_url($email_id) {
$page = apply_filters('newsletter_statistics_view', 'newsletter_statistics_view');
return 'admin.php?page=' . $page . '&amp;id=' . $email_id;
}
function maybe_fix_sent_stats($email) {
global $wpdb;
// Very old emails was missing the send_on
if ($email->send_on == 0) {
$this->query($wpdb->prepare("update " . NEWSLETTER_EMAILS_TABLE . " set send_on=unix_timestamp(created) where id=%d limit 1", $email->id));
$email = $this->get_email($email->id);
}
if ($email->status == 'sending') {
return;
}
if ($email->type == 'followup') {
return;
}
$count = $wpdb->get_var($wpdb->prepare("select count(*) from " . NEWSLETTER_SENT_TABLE . " where email_id=%d", $email->id));
if ($count) {
return;
}
if (empty($email->query)) {
$email->query = "select * from " . NEWSLETTER_USERS_TABLE . " where status='C'";
}
$query = $email->query . " and unix_timestamp(created)<" . $email->send_on;
$query = str_replace('*', 'id, ' . $email->id . ', ' . $email->send_on, $query);
$this->query("insert ignore into " . NEWSLETTER_SENT_TABLE . " (user_id, email_id, time) " . $query);
}
function update_stats($email) {
global $wpdb;
$wpdb->query($wpdb->prepare("update " . $wpdb->prefix . "newsletter_sent s1 join " . $wpdb->prefix . "newsletter_stats s2 on s1.user_id=s2.user_id and s1.email_id=s2.email_id and s1.email_id=%d set s1.open=1, s1.ip=s2.ip", $email->id));
$wpdb->query($wpdb->prepare("update " . $wpdb->prefix . "newsletter_sent s1 join " . $wpdb->prefix . "newsletter_stats s2 on s1.user_id=s2.user_id and s1.email_id=s2.email_id and s2.url<>'' and s1.email_id=%d set s1.open=2, s1.ip=s2.ip", $email->id));
}
function reset_stats($email) {
global $wpdb;
$email_id = $this->to_int_id($email);
$this->query("delete from " . $wpdb->prefix . "newsletter_sent where email_id=" . $email_id);
$this->query("delete from " . $wpdb->prefix . "newsletter_stats where email_id=" . $email_id);
}
function get_total_count($email_id) {
global $wpdb;
return (int) $wpdb->get_var($wpdb->prepare("select count(*) from " . NEWSLETTER_SENT_TABLE . " where email_id=%d", $this->to_int_id($email_id)));
}
function get_open_count($email_id) {
global $wpdb;
return (int) $wpdb->get_var($wpdb->prepare("select count(*) from " . NEWSLETTER_SENT_TABLE . " where open>0 and email_id=%d", $this->to_int_id($email_id)));
}
function get_click_count($email_id) {
global $wpdb;
return (int) $wpdb->get_var($wpdb->prepare("select count(*) from " . NEWSLETTER_SENT_TABLE . " where open>1 and email_id=%d", $this->to_int_id($email_id)));
}
function get_error_count($email_id) {
global $wpdb;
return (int) $wpdb->get_var($wpdb->prepare("select count(*) from " . NEWSLETTER_SENT_TABLE . " where status>0 and email_id=%d", $this->to_int_id($email_id)));
}
function add_click($url, $user_id, $email_id, $ip = null) {
global $wpdb;
if (is_null($ip)) {
$ip = $this->get_remote_ip();
}
$ip = $this->process_ip($ip);
$this->insert(NEWSLETTER_STATS_TABLE, array(
'email_id' => $email_id,
'user_id' => $user_id,
'url' => $url,
'ip' => $ip
)
);
}
function update_open_value($value, $user_id, $email_id, $ip = null) {
global $wpdb;
if (is_null($ip)) {
$ip = $this->get_remote_ip();
}
$ip = $this->process_ip($ip);
$this->query($wpdb->prepare("update " . NEWSLETTER_SENT_TABLE . " set open=%d, ip=%s where email_id=%d and user_id=%d and open<%d limit 1", $value, $ip, $email_id, $user_id, $value));
}
}
NewsletterStatistics::instance();

View File

@@ -0,0 +1,31 @@
<?php
if (!defined('ABSPATH')) exit;
$email_id = (int) $_GET['id'];
$module = NewsletterStatistics::instance();
$email = $module->get_email($email_id);
?>
<div class="wrap" id="tnp-wrap">
<?php include NEWSLETTER_DIR . '/tnp-header.php' ?>
<div id="tnp-heading">
<h2>Retargeting for "<?php echo htmlspecialchars($email->subject); ?>"</h2>
</div>
<div id="tnp-body" style="min-width: 500px">
<p><a href="admin.php?page=newsletter_statistics_view&id=<?php echo $email->id ?>" class="button-primary">Back to the dashboard</a></p>
<a href="https://www.thenewsletterplugin.com/premium?utm_source=plugin&utm_medium=link&utm_content=retarget&utm_campaign=newsletter-reports" target="_blank">
<img style="width: 100%" src="<?php echo plugins_url('newsletter') ?>/statistics/images/retarget.png">
</a>
</div>
<?php include NEWSLETTER_DIR . '/tnp-footer.php' ?>
</div>

View File

@@ -0,0 +1,29 @@
<?php
if (!defined('ABSPATH')) exit;
$email_id = (int) $_GET['id'];
$module = NewsletterStatistics::instance();
$email = $module->get_email($email_id);
?>
<div class="wrap" id="tnp-wrap">
<?php include NEWSLETTER_DIR . '/tnp-header.php' ?>
<div id="tnp-heading">
<h2>Clicked links for "<?php echo esc_html($email->subject); ?>"</h2>
</div>
<div id="tnp-body" style="min-width: 500px">
<p><a href="admin.php?page=newsletter_statistics_view&id=<?php echo $email->id ?>" class="button-primary">Back to the dashboard</a></p>
<p>Clicked link details are available with <a href="https://www.thenewsletterplugin.com/plugins/newsletter/reports-module" target="_blank">Report Extension</a>.</p>
</div>
<?php include NEWSLETTER_DIR . '/tnp-footer.php' ?>
</div>

View File

@@ -0,0 +1,30 @@
<?php
if (!defined('ABSPATH')) exit;
$email_id = (int) $_GET['id'];
$module = NewsletterStatistics::instance();
$email = $module->get_email($email_id);
?>
<div class="wrap" id="tnp-wrap">
<?php include NEWSLETTER_DIR . '/tnp-header.php' ?>
<div id="tnp-heading">
<h2>Reached subscribers for "<?php echo esc_html($email->subject); ?>"</h2>
</div>
<div id="tnp-body" style="min-width: 500px">
<p><a href="admin.php?page=newsletter_statistics_view&id=<?php echo $email->id ?>" class="button-primary">Back to the dashboard</a></p>
<a href="https://www.thenewsletterplugin.com/premium?utm_source=plugin&utm_medium=link&utm_content=audience&utm_campaign=newsletter-reports" target="_blank">
<img src="<?php echo plugins_url('newsletter') ?>/statistics/images/users.png">
</a>
</div>
<?php include NEWSLETTER_DIR . '/tnp-footer.php' ?>
</div>

View File

@@ -0,0 +1,162 @@
<?php
if (!defined('ABSPATH')) exit;
require_once NEWSLETTER_INCLUDES_DIR . '/controls.php';
$module = NewsletterStatistics::instance();
$controls = new NewsletterControls();
wp_enqueue_script('tnp-chart');
$email = $module->get_email($_GET['id']);
//$module->maybe_fix_sent_stats($email);
$module->update_stats($email);
$total_count = $module->get_total_count($email->id);
$open_count = $module->get_open_count($email->id);
$click_count = $module->get_click_count($email->id);
?>
<div class="wrap" id="tnp-wrap">
<?php include NEWSLETTER_DIR . '/tnp-header.php' ?>
<div id="tnp-heading">
<h2><?php _e('Statistics of', 'newsletter') ?> "<?php echo htmlspecialchars($email->subject); ?>"</h2>
</div>
<div id="tnp-body" style="min-width: 500px">
<?php if ($email->status == 'new') { ?>
<div class="tnp-warning"><?php _e('No data, newsletter not sent yet.', 'newsletter')?></div>
<?php } else { ?>
<form action="" method="post">
<?php $controls->init(); ?>
<div class="row">
<div class="col-md-6">
<!-- START Statistics -->
<div class="tnp-widget">
<h3>Subscribers Reached <a href="admin.php?page=newsletter_statistics_view_users&id=<?php echo $email->id ?>">Details</a>
<a href="admin.php?page=newsletter_statistics_view_retarget&id=<?php echo $email->id ?>">Retarget</a></h3>
<div class="inside">
<div class="row tnp-row-pie-charts">
<div class="col-md-6">
<canvas id="tnp-rates1-chart"></canvas>
</div>
<div class="col-md-6">
<canvas id="tnp-rates2-chart"></canvas>
</div>
</div>
<script type="text/javascript">
var rates1 = {
labels: [
"Not opened",
"Opened"
],
datasets: [
{
data: [<?php echo $total_count - $open_count; ?>, <?php echo $open_count; ?>],
backgroundColor: [
"#E67E22",
"#2980B9"
],
hoverBackgroundColor: [
"#E67E22",
"#2980B9"
]
}]};
var rates2 = {
labels: [
"Opened",
"Clicked"
],
datasets: [
{
data: [<?php echo $open_count-$click_count; ?>, <?php echo $click_count; ?>],
backgroundColor: [
"#2980B9",
"#27AE60"
],
hoverBackgroundColor: [
"#2980B9",
"#27AE60"
]
}]};
jQuery(document).ready(function ($) {
ctx1 = $('#tnp-rates1-chart').get(0).getContext("2d");
ctx2 = $('#tnp-rates2-chart').get(0).getContext("2d");
myPieChart1 = new Chart(ctx1, {type: 'pie', data: rates1});
myPieChart2 = new Chart(ctx2, {type: 'pie', data: rates2});
});
</script>
<div class="row tnp-row-values">
<div class="col-md-6">
<div class="tnp-data">
<?php if ($email->status == 'sending' || $email->status == 'paused'): ?>
<div class="tnp-data-title">Sent</div>
<div class="tnp-data-value"><?php echo $email->sent; ?> of <?php echo $email->total; ?></div>
<?php else: ?>
<div class="tnp-data-title">Total Sent</div>
<div class="tnp-data-value"><?php echo $email->sent; ?></div>
<?php endif; ?>
</div>
<!--
<div class="tnp-data">
<div class="tnp-data-title">Interactions</div>
<div class="tnp-data-value"><?php echo $open_count; ?> (<?php echo $module->percent($open_count, $total_count); ?>)</div>
</div>
-->
</div>
<div class="col-md-6">
<div class="tnp-data">
<div class="tnp-data-title">Opened</div>
<div class="tnp-data-value"><?php echo $open_count; ?> (<?php echo $module->percent($open_count, $total_count); ?>)</div>
</div>
<div class="tnp-data">
<div class="tnp-data-title">Clicked</div>
<div class="tnp-data-value"><?php echo $click_count; ?> (<?php echo $module->percent($click_count, $total_count); ?>)</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-6">
<div class="tnp-widget">
<h3>World Map</h3>
<div class="inside">
<a href="https://www.thenewsletterplugin.com/premium?utm_source=plugin&utm_medium=link&utm_content=worldmap&utm_campaign=newsletter-reports" target="_blank">
<img style="width: 100%" src="<?php echo plugins_url('newsletter') ?>/statistics/images/map.gif">
</a>
</div>
</div>
</div>
</div><!-- row -->
</form>
<?php } // if "new" ?>
</div>
<?php include NEWSLETTER_DIR . '/tnp-footer.php' ?>
</div>