<?php
/*
Plugin Name: MailChimp STS
Description: MailChimp STS plugin sends emails, generated by WordPress, through MailChimp's Simple Transactional Service API.
Author: NewClarity
Author URL: http://newclarity.net/
Plugin URL: http://kb.mailchimp.com/connect/wordpress-sts-plugin
Version: 0.9.2
Text Domain: mailchimp-sts
Domain Path: /lang
License Notes: This plugin is released under GPLv2 or later license. This plugin contains Raphael and gRaphael JavaScript libraries, released under GPL-compatible MIT License.
*/
MailChimp_STS::on_load();
class MailChimp_STS {
static $settings;
static $report;
static $stats;
static function on_load() {
define('MAILCHIMP_STS_API_VERSION', '1.0');
add_action('admin_init', array(__CLASS__, 'admin_init'));
add_action('admin_menu', array(__CLASS__, 'admin_menu'));
add_action('admin_notices', array(__CLASS__, 'settings_check'));
add_filter('contextual_help', array(__CLASS__, 'contextual_help'), 10, 3);
add_action('admin_print_footer_scripts', array(__CLASS__,'open_contextual_help'));
load_plugin_textdomain('mailchimp-sts', false, dirname( plugin_basename( __FILE__ ) ).'/lang');
if( function_exists('wp_mail') ) {
// TODO figure out, causes unexpected output on activation because pluggables are loaded already
// trigger_error( __('wp_mail() was already defined by another plugin and could not be defined by MailChimp STS.', 'mailchimp-sts'), E_USER_WARNING );
return;
}
if( self::get_api_key() && self::get_from_email() ) {
function wp_mail( $to, $subject, $message, $headers = '', $attachments = array() ) {
extract( apply_filters( 'wp_mail', compact( 'to', 'subject', 'message', 'headers', 'attachments' ) ) );
if( empty($headers) && empty($attachments) ) {
$sent = MailChimp_STS::wp_mail( $to, $subject, $message );
if( is_wp_error($sent) || 'sent' != $sent['status'] )
return false;
return true;
}
else {
return MailChimp_STS::wp_mail_native( $to, $subject, $message, $headers, $attachments );
}
}
}
}
/**
* @param string|array $to recipients, array or comma-separated string
* @param string $subject email subject
* @param string $message email body
* @return array|WP_Error
*/
static function wp_mail( $to, $subject, $message ) {
$content_type = apply_filters( 'wp_mail_content_type', 'text/plain' );
//$content_type = 'text/html';
if( 'text/html' == $content_type )
$html = $message;
else
$text = $message;
$from_email = self::get_from_email_with_sender_name();
if( is_array($to) )
$to_email = $to;
else
$to_email = explode(',', $to);
$message = compact('html', 'text', 'subject', 'from_name', 'from_email', 'to_email');
return self::SendEmail($message);
}
/**
* @return boolean
*/
static function wp_mail_native( $to, $subject, $message, $headers = '', $attachments = array() ) {
require 'function.wp_mail.php';
}
/**
* @link http://apidocs.mailchimp.com/sts/1.0/sendemail.func.php
*
* @param array $message
* @param boolean $track_opens
* @param boolean $track_clicks
* @param array $tags
* @return array|WP_Error
*/
static function SendEmail( $message, $track_opens = false, $track_clicks = false, $tags = array() ) {
if( !$track_opens )
$track_opens = (bool)self::get_option('track_opens');
if( !$track_clicks )
$track_clicks = (bool)self::get_option('track_clicks');
$tags = self::get_tags($message['subject']);
$args = compact( 'message', 'track_opens', 'track_clicks', 'tags' );
return self::request('SendEmail', $args, 'POST');
}
/**
* @link http://apidocs.mailchimp.com/sts/1.0/verifyemailaddress.func.php
*
* @param string $email
* @return array|WP_Error
*/
static function VerifyEmailAddress($email) {
return self::request('VerifyEmailAddress', array('email' => $email));
}
/**
* @link http://apidocs.mailchimp.com/sts/1.0/deleteverifiedemailaddress.func.php
*
* @param string $email
* @return array|WP_Error
*/
static function DeleteVerifiedEmailAddress($email) {
return self::request('DeleteVerifiedEmailAddress', array('email' => $email));
}
/**
* @link http://apidocs.mailchimp.com/sts/1.0/listverifiedemailaddresses.func.php
*
* @return array|WP_Error
*/
static function ListVerifiedEmailAddresses() {
return self::request('ListVerifiedEmailAddresses');
}
/**
* @link http://apidocs.mailchimp.com/sts/1.0/getsendquota.func.php
*
* @return array|WP_Error
*/
static function GetSendQuota() {
return self::request('GetSendQuota');
}
/**
* @link http://apidocs.mailchimp.com/sts/1.0/getsendstatistics.func.php
*
* @return array|WP_Error
*/
static function GetSendStatistics() {
return self::request('GetSendStatistics');
}
/**
* @link http://apidocs.mailchimp.com/sts/1.0/
*
* @param string $method API method name
* @param array $args query arguments
* @param string $http GET or POST request type
* @param string $output API response format (json,php,xml,yaml). json and xml are decoded into arrays automatically.
* @return array|string|WP_Error
*/
static function request($method, $args = array(), $http = 'GET', $output = 'json') {
if( !isset($args['apikey']) )
$args['apikey'] = MailChimp_STS::get_api_key();
$datacenter = MailChimp_STS::get_datacenter($args['apikey']);
$api_version = MAILCHIMP_STS_API_VERSION;
$dot_output = ('json' == $output) ? '' : ".{$output}";
$url = "http://{$datacenter}.sts.mailchimp.com/{$api_version}/{$method}{$dot_output}";
switch ($http) {
case 'GET':
$url .= '?' . http_build_query($args);
$response = wp_remote_get($url);
break;
case 'POST':
$response = wp_remote_post($url, array('body' => $args));
break;
default:
return new WP_Error('', __('Unknown request type', 'mailchimp-sts'));
break;
}
$response_code = wp_remote_retrieve_response_code($response);
$body = wp_remote_retrieve_body($response);
switch ($output) {
case 'json':
$body = json_decode($body, true);
break;
case 'php':
$body = unserialize($body);
break;
}
if( 200 == $response_code ) {
return $body;
}
else {
$message = isset( $body['message'] ) ? $body['message'] : '' ;
return new WP_Error($response_code, $message, $body );
}
}
/**
* @return mixed
*/
static function get_option( $name, $default = false ) {
$options = get_option('mailchimp-sts');
if( isset( $options[$name] ) )
return $options[$name];
return $default;
}
/**
* @return boolean
*/
static function set_option( $name, $value ) {
$options = get_option('mailchimp-sts');
$options[$name] = $value;
return update_option('mailchimp-sts', $options);
}
/**
* @return string|boolean
*/
static function get_api_key() {
return self::get_option('api_key');
}
/**
* @param string $key
* @return string|boolean
*/
static function get_datacenter($key = false) {
if( !$key )
$key = self::get_api_key();
if( $key ) {
$pos = strpos($key, '-');
if( false === $pos )
return false;
return substr( $key, $pos+1 );
}
return false;
}
static function get_from_email_with_sender_name() {
return self::get_sender_name() . ' <' . self::get_option('from_email') . '>';
}
/**
* @return string|boolean
*/
static function get_from_email() {
return self::get_option('from_email') ;
}
/**
* @return string|boolean
*/
static function get_sender_name() {
return self::get_option('sender_name');
}
/**
* @param string $subject
* @return array
*/
static function get_tags($subject) {
$tags = array();
$trace = debug_backtrace();
$level = 4;
$function = $trace[$level]['function'];
if( 'include' == $function || 'require' == $function ) {
$file = basename($trace[$level]['args'][0]);
$tags[] = "wp-{$file}";
}
else {
if( isset( $trace[$level]['class'] ) )
$function = $trace[$level]['class'].$trace[$level]['type'].$function;
$tags[] = "wp-{$function}";
}
return apply_filters('mailchimp_sts_tags', $tags);
}
/**
* @return boolean
*/
static function is_plugin_page() {
return ( isset( $_GET['page'] ) && $_GET['page'] == 'mailchimp-sts' );
}
/**
* Sets up options page and sections.
*/
static function admin_init() {
add_filter('plugin_action_links',array(__CLASS__,'plugin_action_links'), 10,5);
add_action('admin_enqueue_scripts', array(__CLASS__,'admin_enqueue_scripts'));
register_setting('mailchimp-sts', 'mailchimp-sts', array(__CLASS__,'form_validate'));
// API Settings
add_settings_section('mailchimp-sts-api', __('API Settings', 'mailchimp-sts'), '__return_false', 'mailchimp-sts');
add_settings_field('api-version', __('API version', 'mailchimp-sts'), array(__CLASS__, 'api_version'), 'mailchimp-sts', 'mailchimp-sts-api');
if( self::get_datacenter() )
add_settings_field('api-datacenter', __('API data center', 'mailchimp-sts'), array(__CLASS__, 'api_datacenter'), 'mailchimp-sts', 'mailchimp-sts-api');
add_settings_field('api-key', __('API key', 'mailchimp-sts'), array(__CLASS__, 'api_key'), 'mailchimp-sts', 'mailchimp-sts-api');
if( self::get_api_key() ) {
// Tracking Settings
add_settings_section('mailchimp-sts-tracking', __('Tracking Settings', 'mailchimp-sts'), '__return_false', 'mailchimp-sts');
add_settings_field('track-opens', __('Email opens', 'mailchimp-sts'), array(__CLASS__, 'track_opens'), 'mailchimp-sts', 'mailchimp-sts-tracking');
add_settings_field('track-clicks', __('Email clicks', 'mailchimp-sts'), array(__CLASS__, 'track_clicks'), 'mailchimp-sts', 'mailchimp-sts-tracking');
// Verified Addresses
add_settings_section('mailchimp-sts-addresses', __('Verified Addresses', 'mailchimp-sts'), '__return_false', 'mailchimp-sts');
add_settings_field('from-email', __('Email addresses', 'mailchimp-sts'), array(__CLASS__, 'from_email'), 'mailchimp-sts', 'mailchimp-sts-addresses');
add_settings_field('verify-email', __('Add address', 'mailchimp-sts'), array(__CLASS__, 'verify_email'), 'mailchimp-sts', 'mailchimp-sts-addresses');
add_settings_field('sender-name', __('Sender name', 'mailchimp-sts'), array(__CLASS__, 'sender_name'), 'mailchimp-sts', 'mailchimp-sts-addresses');
// Email Test
register_setting('mailchimp-sts-test', 'mailchimp-sts-test', array(__CLASS__, 'test_email'));
add_settings_section('mailchimp-email-test', __('Email Test', 'mailchimp-sts'), '__return_false', 'mailchimp-sts-test');
add_settings_field('email-to', __('Send to', 'mailchimp-sts'), array(__CLASS__, 'email_to'), 'mailchimp-sts-test', 'mailchimp-email-test');
add_settings_field('email-subject', __('Subject', 'mailchimp-sts'), array(__CLASS__, 'email_subject'), 'mailchimp-sts-test', 'mailchimp-email-test');
add_settings_field('email-message', __('Message', 'mailchimp-sts'), array(__CLASS__, 'email_message'), 'mailchimp-sts-test', 'mailchimp-email-test');
}
}
/**
* Creates option page's entry in Settings section of menu.
*/
static function admin_menu() {
self::$settings = add_options_page( __('MailChimp STS Settings', 'mailchimp-sts'), __('MailChimp STS', 'mailchimp-sts'), 'manage_options', 'mailchimp-sts', array(__CLASS__,'options_page'));
self::$report = add_dashboard_page( __('MailChimp STS Reports', 'mailchimp-sts'),__('STS Report', 'mailchimp-sts'),'manage_options','mailchimp-sts-report', array(__CLASS__,'report_page'));
add_action('admin_footer-'.self::$report, array(__CLASS__,'report_script'));
}
static function admin_enqueue_scripts($hook_suffix) {
if( $hook_suffix != self::$report )
return;
$suffix = defined('SCRIPT_DEBUG') && SCRIPT_DEBUG ? '' : '-min';
wp_register_script('mailchimp-raphael', plugins_url("js/raphael{$suffix}.js", __FILE__), array(), null, true);
wp_register_script('mailchimp-graphael', plugins_url("js/g.raphael{$suffix}.js", __FILE__), array('mailchimp-raphael'), null, true);
wp_register_script('mailchimp-graphael-line', plugins_url("js/g.line{$suffix}.js", __FILE__), array('mailchimp-graphael'), null, true);
wp_enqueue_script('mailchimp-graphael-line');
}
/**
* Generates source of contextual help panel.
*/
static function contextual_help($contextual_help, $screen_id, $screen) {
if ($screen_id == self::$settings) {
return '<p>' . __('To use the plugin you will need:', 'mailchimp-sts') . '</p>'
. '<ol>'
. '<li>'. __('<strong>MailChimp account</strong> and API key.', 'mailchimp-sts') . '</li>'
. '<li>' . __('<strong>Amazon SES account</strong> with production access, integrated with MailChimp.', 'mailchimp-sts') . '</li>'
. '<li>' . __('<strong>Verified email address</strong> to use as sender for email.', 'mailchimp-sts') . '</li>'
. '</ol>'
. '<p>' . __('For detailed setup instructions please see ', 'mailchimp-sts') . '<a href="'.plugins_url('readme.html',__FILE__).'">readme.html</a>.</p>'
. '<p>' . __('Also note that emails using custom headers (such as <em>cc</em> or <em>bcc</em>) and/or attachments are not supported by STS and will be sent directly.', 'mailchimp-sts') . '</p>'
. '<p>' . __('Support:', 'mailchimp-sts').'</p>'
. '<ul>'
. '<li>' . __('Ask your <strong>How To</strong> questions on <a href="http://wordpress.stackexchange.com/questions/ask?title=MailChimp%20STS&tags=mailchimp-sts">StackExchange WordPress Answers site</a>.','mailchimp-sts') . '</li>'
. '<li>' . __('Ask your <strong>Installation</strong> questions and submit <strong>Bug Reports</strong> on <a href="http://wordpress.org/tags/mailchimp-sts?forum_id=10">WordPress.org support forums</a>.','mailchimp-sts') . '</li>'
. '</ul>'
;
}
return $contextual_help;
}
/**
* Adds link to settings page in list of plugins
*/
static function plugin_action_links($actions, $plugin_file) {
static $plugin;
if (!isset($plugin))
$plugin = plugin_basename(__FILE__);
if ($plugin == $plugin_file) {
$settings = array('settings' => '<a href="options-general.php?page=mailchimp-sts">' . __('Settings', 'mailchimp-sts') . '</a>');
$report = array('report' => '<a href="index.php?page=mailchimp-sts-report">' . __('Report', 'mailchimp-sts') . '</a>');
$actions = array_merge($settings, $actions, $report);
}
return $actions;
}
/**
* Generates source of options page.
*/
static function options_page() {
if (!current_user_can('manage_options'))
wp_die( __('You do not have sufficient permissions to access this page.') );
?>
<div class="wrap">
<div class="icon32" style="background: url('<?php echo plugins_url('images/light_freddie.png',__FILE__); ?>');"><br /></div>
<h2><?php _e('MailChimp Simple Transactional Service Settings', 'mailchimp-sts'); ?></h2>
<form method="post" action="options.php">
<?php settings_fields('mailchimp-sts'); ?>
<?php do_settings_sections('mailchimp-sts'); ?>
<p class="submit"><input type="submit" name="Submit" class="button-primary" value="<?php esc_attr_e('Save Changes') ?>" /></p>
</form>
<form method="post" action="options.php">
<?php settings_fields('mailchimp-sts-test'); ?>
<?php do_settings_sections('mailchimp-sts-test'); ?>
<?php if( self::get_api_key() ) {
?><p class="submit"><input type="submit" name="Submit" class="button-primary" value="<?php esc_attr_e('Send Email') ?>" /></p><?php
} ?>
</form>
</div>
<?php
}
static function report_page() {
if (!current_user_can('manage_options'))
wp_die( __('You do not have sufficient permissions to access this page.') );
?>
<div class="wrap">
<div class="icon32" style="background: url('<?php echo plugins_url('images/light_freddie.png',__FILE__); ?>');"><br /></div>
<h2><?php _e('MailChimp Simple Transactional Service Report', 'mailchimp-sts'); ?></h2>
<?php
$stats = get_transient('mailchimp-sts-stats');
if (false === $stats) {
$response = self::GetSendStatistics();
if (!is_wp_error($response)) {
$stats = $response;
set_transient('mailchimp-sts-stats', $stats, 60 * 15);
}
else {
echo '<p>' . __('There was a problem retrieving statistics.', 'mailchimp-sts') . '</p>';
echo '</div>';
return;
}
}
//var_dump($stats);
if( empty($stats) )
$stats = array();
$days = array();
foreach( $stats as $node ) {
$timestamp = $node['Timestamp'];
$timestamp = strtotime($timestamp);
$day = date('M j', $timestamp);
if( !isset($days[$day]) )
$days[$day] = (int)$node['DeliveryAttempts'];
else
$days[$day] += (int)$node['DeliveryAttempts'];
}
$data = array();
$current = strtotime('-13 days');
$end = time();
while( $current <= $end ) {
$key = date('M j', $current);
$data[$key] = isset($days[$key]) ? $days[$key]: 0;
$current = strtotime('+1 day', $current);
}
self::$stats = $data;
// var_dump($data);
?>
<h3><?php _e('Sends Over Time', 'mailchimp-sts'); ?></h3>
<div id="#emails-sent"></div>
</div>
<?php
}
static function report_script() {
$x = implode(',',range(1, count(self::$stats)));
$y = implode(',',self::$stats);
$labels = array_keys(self::$stats);
foreach( $labels as $key=>$label )
$labels[$key] = "\"{$label}\"";
$labels = implode( ',', $labels );
?>
<script type="text/javascript">
var r = Raphael('#emails-sent');
var linechart = r.g.linechart(10,10,600,300,[<?php echo $x; ?>],[<?php echo $y; ?>], {"colors":["#21759B"], "symbol":"o"});
r.g.axis(30,300,280,0,<?php echo max(self::$stats); ?>,5,1,"","-");
r.g.axis(40,310,560,0,300,13,0,[<?php echo $labels; ?>], "-");
</script>
<?php
}
/**
* Processes submitted settings from.
*/
static function form_validate($input) {
self::settings_check($input['api_key']);
if( isset($input['verify_email']) && !empty( $input['verify_email'] ) ) {
$verify = self::VerifyEmailAddress( $input['verify_email'] );
if( is_wp_error($verify) )
add_settings_error ('verify-email', '', __('Email verification request failed ', 'mailchimp-sts').$verify->get_error_message());
else
add_settings_error('verify-email', '', sprintf('Email verification request sent to <em>%s</em>', $input['verify_email']), 'updated');
unset($input['verify_email']);
}
return array_map('wp_strip_all_tags', $input);
}
/**
* Processes submitted email test form.
*/
static function test_email($input) {
if (isset($input['email_to']) && !empty($input['email_to'])) {
$to = $input['email_to'];
$subject = isset($input['email_subject']) ? $input['email_subject'] : '';
$message = isset($input['email_message']) ? $input['email_message'] : '';
$test = self::wp_mail($to, $subject, $message);
if (is_wp_error($test)) {
add_settings_error('email-to', 'email-to', __('Test email send failed. ', 'mailchimp-sts') . $test->get_error_message());
return array_map('wp_strip_all_tags', $input);
}
elseif ('sent' != $test['status']) {
add_settings_error('email-to', 'email-to', __('Test email send failed. ', 'mailchimp-sts') . $test['msg']);
return array_map('wp_strip_all_tags', $input);
}
else
add_settings_error('email-to', 'email-to', __('Test email sent.', 'mailchimp-sts'), 'updated');
}
return array();
}
/**
* Determines if key is valid, is account sandboxed and generates appropriate notices.
*/
static function settings_check($key = false) {
if( !$key )
if( !self::is_plugin_page() )
return;
else
$key = self::get_api_key();
if( !$key )
return;
if( !self::get_datacenter($key) ) {
add_settings_error('api-key', 'api-key-error', __('Cannot determine data center. Please check API key.', 'mailchimp-sts') );
return;
}
$quota = self::request('GetSendQuota', array('apikey' => $key));
if( is_wp_error($quota) )
add_settings_error('api-key', 'api-key-error', __('API error. ', 'mailchimp-sts').$quota->get_error_message() );
else
if( isset( $quota['Max24HourSend'] ) && 200 >= (int)$quota['Max24HourSend'] )
add_settings_error('api-key', 'api-key-sandbox', __('Your Amazon SES account seems to be in sandbox mode. <a href="http://aws.amazon.com/ses/fullaccessrequest">Request production access</a> to be able to send emails to unverified addresses.', 'mailchimp-sts'), 'updated');
}
// Following methods generate parts of settings and test forms.
static function api_version() {
echo MAILCHIMP_STS_API_VERSION;
}
static function api_datacenter() {
echo self::get_datacenter();
}
static function api_key() {
$key = self::get_api_key();
?>
<input id='api_key' name='mailchimp-sts[api_key]' size='45' type='text' value='<?php echo esc_attr($key); ?>' /><br />
<span class="setting-description"><em><?php _e('Get by visiting <a href="http://admin.mailchimp.com/account/api-key-popup">your API dashboard</a>.'); ?></em></span>
<?php
}
static function track_opens() {
$track_opens = self::get_option('track_opens');
?><input id='track_opens' name='mailchimp-sts[track_opens]' type='checkbox' value='track' <?php checked($track_opens,'track') ?> /> <?php _e('track'); ?><br /><?php
}
static function track_clicks() {
$track_clicks = self::get_option('track_clicks');
?><input id='track_clicks' name='mailchimp-sts[track_clicks]' type='checkbox' value='track' <?php checked($track_clicks,'track') ?> /> <?php _e('track'); ?><br /><?php
}
static function from_email() {
$from_email = self::get_from_email();
$addresses = self::ListVerifiedEmailAddresses();
if ( !is_wp_error($addresses) && isset($addresses['email_addresses'])) {
$addresses = $addresses['email_addresses'];
foreach( $addresses as $key => $address )
if( false !== strpos($address, 'bounces.transact.mcsv.net') )
unset( $addresses[$key] );
}
if( is_wp_error($addresses) || empty($addresses) ) {
_e('No verified email found.');
if( $from_email )
self::set_option('from_email', false);
return;
}
if( !$from_email || !in_array($from_email, $addresses) ) {
$from_email = reset($addresses);
self::set_option('from_email', $from_email);
}
?><span class="setting-description"><em><?php _e('Selected address will be used as sender for outgoing email:'); ?></em></span><br /><?php
foreach( $addresses as $address ) {
?><input name="mailchimp-sts[from_email]" type="radio" value="<?php esc_attr_e($address); ?>" <?php checked($address, $from_email); ?>> <?php esc_html_e($address); ?><br /><?php
}
}
static function sender_name() {
$sender_name = self::get_sender_name();
echo "<input id='sender_name' name='mailchimp-sts[sender_name]' size='45' type='text' value='" . esc_attr($sender_name) . "' /><br />";
}
static function verify_email() {
?><input id='verify_email' name='mailchimp-sts[verify_email]' size='45' type='text' /><?php
}
/**
* @param string $field
* @return string|bool
*/
static function get_test_email($field) {
$email = get_option('mailchimp-sts-test');
if( isset( $email[$field] ) )
return $email[$field];
return false;
}
static function email_to() {
?><input id='email_to' name='mailchimp-sts-test[email_to]' size='45' type='text' value="<?php esc_attr_e( self::get_test_email('email_to') ); ?>" /><?php
}
static function email_subject() {
?><input id='email_subject' name='mailchimp-sts-test[email_subject]' size='45' type='text' value="<?php esc_attr_e( self::get_test_email('email_subject') ); ?>" /><?php
}
static function email_message() {
?><textarea rows="5" cols="45" name="mailchimp-sts-test[email_message]" ><?php esc_html_e( self::get_test_email('email_message') ); ?></textarea><?php
}
/**
* Opens contextual help section.
*/
static function open_contextual_help() {
if (!self::is_plugin_page() || (self::get_api_key() && self::get_from_email() ))
return;
?>
<script type="text/javascript">
jQuery(document).bind( 'ready', function() {
jQuery('a#contextual-help-link').trigger('click');
});
</script>
<?php
}
}
?>