*/
class MailChimp_WooCommerce_Admin extends MailChimp_WooCommerce_Options {
/**
* @return MailChimp_WooCommerce_Admin
*/
public static function connect()
{
$env = mailchimp_environment_variables();
return new self('mailchimp-woocommerce', $env->version);
}
/**
* Initialize the class and set its properties.
*
* @since 1.0.0
* @param string $plugin_name The name of this plugin.
* @param string $version The version of this plugin.
*/
public function __construct( $plugin_name, $version ) {
$this->plugin_name = $plugin_name;
$this->version = $version;
}
/**
* Register the stylesheets for the admin area.
*
* @since 1.0.0
*/
public function enqueue_styles() {
wp_enqueue_style( $this->plugin_name, plugin_dir_url( __FILE__ ) . 'css/mailchimp-woocommerce-admin.css', array(), $this->version, 'all' );
}
/**
* Register the JavaScript for the admin area.
*
* @since 1.0.0
*/
public function enqueue_scripts() {
wp_enqueue_script( $this->plugin_name, plugin_dir_url( __FILE__ ) . 'js/mailchimp-woocommerce-admin.js', array( 'jquery' ), $this->version, false );
}
/**
* Register the administration menu for this plugin into the WordPress Dashboard menu.
*
* @since 1.0.0
*/
public function add_plugin_admin_menu() {
add_menu_page(
'MailChimp - WooCommerce Setup',
'MailChimp',
'manage_options',
$this->plugin_name,
array($this, 'display_plugin_setup_page'),
'data:image/svg+xml;base64,'.$this->mailchimp_svg()
);
}
/**
* @return string
*/
protected function mailchimp_svg()
{
return base64_encode('
');
}
/**
* Add settings action link to the plugins page.
*
* @since 1.0.0
*/
public function add_action_links($links) {
$settings_link = array(
'' . __('Settings', $this->plugin_name) . '',
);
return array_merge($settings_link, $links);
}
/**
* Render the settings page for this plugin.
*
* @since 1.0.0
*/
public function display_plugin_setup_page() {
include_once( 'partials/mailchimp-woocommerce-admin-tabs.php' );
}
/**
*
*/
public function options_update() {
$this->handle_abandoned_cart_table();
register_setting($this->plugin_name, $this->plugin_name, array($this, 'validate'));
}
/**
* Depending on the version we're on we may need to run some sort of migrations.
*/
public function update_db_check() {
// grab the current version set in the plugin variables
$version = mailchimp_environment_variables()->version;
// grab the saved version or default to 1.0.3 since that's when we first did this.
$saved_version = get_site_option('mailchimp_woocommerce_version', '1.0.3');
// if the saved version is less than the current version
if (version_compare($version, $saved_version) > 0) {
// resave the site option so this only fires once.
update_site_option('mailchimp_woocommerce_version', $version);
}
}
/**
* We need to do a tidy up function on the mailchimp_carts table to
* remove anything older than 30 days.
*
* Also if we don't have the configuration set, we need to create the table.
*/
protected function handle_abandoned_cart_table()
{
global $wpdb;
if (get_site_option('mailchimp_woocommerce_db_mailchimp_carts', false)) {
// need to tidy up the mailchimp_cart table and make sure we don't have anything older than 30 days old.
$date = gmdate( 'Y-m-d H:i:s', strtotime(date ("Y-m-d") ."-30 days"));
$sql = $wpdb->prepare("DELETE FROM {$wpdb->prefix}mailchimp_carts WHERE created_at <= %s", $date);
$wpdb->query($sql);
} else {
// create the table for the first time now.
$charset_collate = $wpdb->get_charset_collate();
$table = "{$wpdb->prefix}mailchimp_carts";
$sql = "CREATE TABLE IF NOT EXISTS $table (
id VARCHAR (255) NOT NULL,
email VARCHAR (100) NOT NULL,
user_id INT (11) DEFAULT NULL,
cart text NOT NULL,
created_at datetime NOT NULL
) $charset_collate;";
if (($result = $wpdb->query($sql)) > 0) {
update_site_option('mailchimp_woocommerce_db_mailchimp_carts', true);
}
}
}
/**
* @param $input
* @return array
*/
public function validate($input) {
$active_tab = isset($input['mailchimp_active_tab']) ? $input['mailchimp_active_tab'] : null;
if (empty($active_tab)) {
return $this->getOptions();
}
switch ($active_tab) {
case 'api_key':
$data = $this->validatePostApiKey($input);
break;
case 'store_info':
$data = $this->validatePostStoreInfo($input);
break;
case 'campaign_defaults' :
$data = $this->validatePostCampaignDefaults($input);
break;
case 'newsletter_settings':
$data = $this->validatePostNewsletterSettings($input);
break;
case 'sync':
// remove all the pointers to be sure
$service = new MailChimp_Service();
$service->removePointers(true, true);
$this->startSync();
$this->showSyncStartedMessage();
$this->setData('sync.config.resync', true);
break;
case 'logs':
if (isset($_POST['mc_action']) && in_array($_POST['mc_action'], array('view_log', 'remove_log'))) {
wp_redirect('options-general.php?page=mailchimp-woocommerce&tab=logs');
exit();
}
$data = array(
'mailchimp_logging' => isset($input['mailchimp_logging']) ? $input['mailchimp_logging'] : 'none',
);
break;
}
return (isset($data) && is_array($data)) ? array_merge($this->getOptions(), $data) : $this->getOptions();
}
/**
* STEP 1.
*
* Handle the 'api_key' tab post.
*
* @param $input
* @return array
*/
protected function validatePostApiKey($input)
{
$data = array(
'mailchimp_api_key' => isset($input['mailchimp_api_key']) ? $input['mailchimp_api_key'] : false,
'mailchimp_debugging' => isset($input['mailchimp_debugging']) ? $input['mailchimp_debugging'] : false,
'mailchimp_account_info_id' => null,
'mailchimp_account_info_username' => null,
);
$api = new MailChimp_WooCommerce_MailChimpApi($data['mailchimp_api_key']);
$valid = true;
if (empty($data['mailchimp_api_key']) || !($profile = $api->ping(true))) {
unset($data['mailchimp_api_key']);
$valid = false;
if (!$profile) {
add_settings_error('mailchimp_store_settings', '', 'API Key Invalid');
}
}
// tell our reporting system whether or not we had a valid ping.
$this->setData('validation.api.ping', $valid);
$data['active_tab'] = $valid ? 'store_info' : 'api_key';
if ($valid && isset($profile) && is_array($profile) && array_key_exists('account_id', $profile)) {
$data['mailchimp_account_info_id'] = $profile['account_id'];
$data['mailchimp_account_info_username'] = $profile['username'];
}
return $data;
}
/**
* STEP 2.
*
* Handle the 'store_info' tab post.
*
* @param $input
* @return array
*/
protected function validatePostStoreInfo($input)
{
$data = $this->compileStoreInfoData($input);
if (!$this->hasValidStoreInfo($data)) {
if ($this->hasInvalidStoreAddress($data)) {
$this->addInvalidAddressAlert();
}
if ($this->hasInvalidStorePhone($data)) {
$this->addInvalidPhoneAlert();
}
if ($this->hasInvalidStoreName($data)) {
$this->addInvalidStoreNameAlert();
}
$this->setData('validation.store_info', false);
$data['active_tab'] = 'store_info';
return array();
}
$this->setData('validation.store_info', true);
$data['active_tab'] = 'campaign_defaults';
if ($this->hasValidMailChimpList()) {
$this->syncStore(array_merge($this->getOptions(), $data));
}
return $data;
}
/**
* @param $input
* @return array
*/
protected function compileStoreInfoData($input)
{
return array(
// store basics
'store_name' => trim((isset($input['store_name']) ? $input['store_name'] : get_option('blogname'))),
'store_street' => isset($input['store_street']) ? $input['store_street'] : false,
'store_city' => isset($input['store_city']) ? $input['store_city'] : false,
'store_state' => isset($input['store_state']) ? $input['store_state'] : false,
'store_postal_code' => isset($input['store_postal_code']) ? $input['store_postal_code'] : false,
'store_country' => isset($input['store_country']) ? $input['store_country'] : false,
'store_phone' => isset($input['store_phone']) ? $input['store_phone'] : false,
// locale info
'store_locale' => isset($input['store_locale']) ? $input['store_locale'] : false,
'store_timezone' => isset($input['store_timezone']) ? $input['store_timezone'] : false,
'store_currency_code' => isset($input['store_currency_code']) ? $input['store_currency_code'] : false,
'admin_email' => isset($input['admin_email']) && is_email($input['admin_email']) ? $input['admin_email'] : $this->getOption('admin_email', false),
);
}
/**
* @param array $data
* @return array|bool
*/
protected function hasInvalidStoreAddress($data)
{
$address_keys = array(
'admin_email',
'store_city',
'store_state',
'store_postal_code',
'store_country',
'store_street'
);
$invalid = array();
foreach ($address_keys as $address_key) {
if (empty($data[$address_key])) {
$invalid[] = $address_key;
}
}
return empty($invalid) ? false : $invalid;
}
/**
* @param $data
* @return bool
*/
protected function hasInvalidStorePhone($data)
{
if (empty($data['store_phone']) || strlen($data['store_phone']) <= 6) {
return true;
}
return false;
}
/**
* @param $data
* @return bool
*/
protected function hasInvalidStoreName($data)
{
if (empty($data['store_name'])) {
return true;
}
return false;
}
/**
*
*/
protected function addInvalidAddressAlert()
{
add_settings_error('mailchimp_store_settings', '', 'As part of the MailChimp Terms of Use, we require a contact email and a physical mailing address.');
}
/**
*
*/
protected function addInvalidPhoneAlert()
{
add_settings_error('mailchimp_store_settings', '', 'As part of the MailChimp Terms of Use, we require a valid phone number for your store.');
}
/**
*
*/
protected function addInvalidStoreNameAlert()
{
add_settings_error('mailchimp_store_settings', '', 'MailChimp for WooCommerce requires a Store Name to connect your store.');
}
/**
* STEP 3.
*
* Handle the 'campaign_defaults' tab post.
*
* @param $input
* @return array
*/
protected function validatePostCampaignDefaults($input)
{
$data = array(
'campaign_from_name' => isset($input['campaign_from_name']) ? $input['campaign_from_name'] : false,
'campaign_from_email' => isset($input['campaign_from_email']) && is_email($input['campaign_from_email']) ? $input['campaign_from_email'] : false,
'campaign_subject' => isset($input['campaign_subject']) ? $input['campaign_subject'] : get_option('blogname'),
'campaign_language' => isset($input['campaign_language']) ? $input['campaign_language'] : 'en',
'campaign_permission_reminder' => isset($input['campaign_permission_reminder']) ? $input['campaign_permission_reminder'] : 'You were subscribed to the newsletter from '.get_option('blogname'),
);
if (!$this->hasValidCampaignDefaults($data)) {
$this->setData('validation.campaign_defaults', false);
return array('active_tab' => 'campaign_defaults');
}
$this->setData('validation.campaign_defaults', true);
$data['active_tab'] = 'newsletter_settings';
return $data;
}
/**
* STEP 4.
*
* Handle the 'newsletter_settings' tab post.
*
* @param $input
* @return array
*/
protected function validatePostNewsletterSettings($input)
{
// default value.
$checkbox = $this->getOption('mailchimp_checkbox_defaults', 'check');
// see if it's posted in the form.
if (isset($input['mailchimp_checkbox_defaults']) && !empty($input['mailchimp_checkbox_defaults'])) {
$checkbox = $input['mailchimp_checkbox_defaults'];
}
$data = array(
'mailchimp_list' => isset($input['mailchimp_list']) ? $input['mailchimp_list'] : $this->getOption('mailchimp_list', ''),
'newsletter_label' => isset($input['newsletter_label']) ? $input['newsletter_label'] : $this->getOption('newsletter_label', 'Subscribe to our newsletter'),
'mailchimp_auto_subscribe' => isset($input['mailchimp_auto_subscribe']) ? (bool) $input['mailchimp_auto_subscribe'] : $this->getOption('mailchimp_auto_subscribe', '0'),
'mailchimp_checkbox_defaults' => $checkbox,
'mailchimp_checkbox_action' => isset($input['mailchimp_checkbox_action']) ? $input['mailchimp_checkbox_action'] : $this->getOption('mailchimp_checkbox_action', 'woocommerce_after_checkout_billing_form'),
'mailchimp_product_image_key' => isset($input['mailchimp_product_image_key']) ? $input['mailchimp_product_image_key'] : 'medium',
);
if ($data['mailchimp_list'] === 'create_new') {
$data['mailchimp_list'] = $this->createMailChimpList(array_merge($this->getOptions(), $data));
}
// as long as we have a list set, and it's currently in MC as a valid list, let's sync the store.
if (!empty($data['mailchimp_list']) && $this->api()->hasList($data['mailchimp_list'])) {
$this->setData('validation.newsletter_settings', true);
// sync the store with MC
$this->syncStore(array_merge($this->getOptions(), $data));
// start the sync automatically if the sync is false
if ((bool) $this->getData('sync.started_at', false) === false) {
$this->startSync();
$this->showSyncStartedMessage();
}
$data['active_tab'] = 'sync';
return $data;
}
$this->setData('validation.newsletter_settings', false);
$data['active_tab'] = 'newsletter_settings';
return $data;
}
/**
* @param null|array $data
* @return bool
*/
public function hasValidStoreInfo($data = null)
{
return $this->validateOptions(array(
'store_name', 'store_street', 'store_city', 'store_state',
'store_postal_code', 'store_country', 'store_phone',
'store_locale', 'store_timezone', 'store_currency_code',
'store_phone',
), $data);
}
/**
* @param null|array $data
* @return bool
*/
public function hasValidCampaignDefaults($data = null)
{
return $this->validateOptions(array(
'campaign_from_name', 'campaign_from_email', 'campaign_subject', 'campaign_language',
'campaign_permission_reminder'
), $data);
}
/**
* @param null|array $data
* @return bool
*/
public function hasValidApiKey($data = null)
{
if (!$this->validateOptions(array('mailchimp_api_key'), $data)) {
return false;
}
if (($pinged = $this->getCached('api-ping-check', null)) === null) {
if (($pinged = $this->api()->ping())) {
$this->setCached('api-ping-check', true, 120);
}
return $pinged;
}
return $pinged;
}
/**
* @return bool
*/
public function hasValidMailChimpList()
{
if (!$this->hasValidApiKey()) {
add_settings_error('mailchimp_api_key', '', 'You must supply your MailChimp API key to pull the lists.');
return false;
}
if (!($this->validateOptions(array('mailchimp_list')))) {
return $this->api()->getLists(true);
}
return $this->api()->hasList($this->getOption('mailchimp_list'));
}
/**
* @return array|bool|mixed|null
*/
public function getAccountDetails()
{
if (!$this->hasValidApiKey()) {
return false;
}
try {
if (($account = $this->getCached('api-account-name', null)) === null) {
if (($account = $this->api()->getProfile())) {
$this->setCached('api-account-name', $account, 120);
}
}
return $account;
} catch (\Exception $e) {
return false;
}
}
/**
* @return array|bool
*/
public function getMailChimpLists()
{
if (!$this->hasValidApiKey()) {
return false;
}
try {
if (($pinged = $this->getCached('api-lists', null)) === null) {
$pinged = $this->api()->getLists(true);
if ($pinged) {
$this->setCached('api-lists', $pinged, 120);
}
return $pinged;
}
return $pinged;
} catch (\Exception $e) {
return array();
}
}
/**
* @return array|bool
*/
public function getListName()
{
if (!$this->hasValidApiKey()) {
return false;
}
if (!($list_id = $this->getOption('mailchimp_list', false))) {
return false;
}
try {
if (($lists = $this->getCached('api-lists', null)) === null) {
$lists = $this->api()->getLists(true);
if ($lists) {
$this->setCached('api-lists', $lists, 120);
}
}
return array_key_exists($list_id, $lists) ? $lists[$list_id] : false;
} catch (\Exception $e) {
return array();
}
}
/**
* @return bool
*/
public function isReadyForSync()
{
if (!$this->hasValidApiKey()) {
return false;
}
if (!$this->getOption('mailchimp_list', false)) {
return false;
}
if (!$this->api()->hasList($this->getOption('mailchimp_list'))) {
return false;
}
if (!$this->api()->getStore($this->getUniqueStoreID())) {
return false;
}
return true;
}
/**
* @param null|array $data
* @return bool|string
*/
private function createMailChimpList($data = null)
{
if (empty($data)) {
$data = $this->getOptions();
}
$required = array(
'store_name', 'store_street', 'store_city', 'store_state',
'store_postal_code', 'store_country', 'campaign_from_name',
'campaign_from_email', 'campaign_subject', 'campaign_permission_reminder',
);
foreach ($required as $requirement) {
if (!isset($data[$requirement]) || empty($data[$requirement])) {
return false;
}
}
$submission = new MailChimp_WooCommerce_CreateListSubmission();
// allow the subscribers to choose preferred email type (html or text).
$submission->setEmailTypeOption(true);
// set the store name
$submission->setName($data['store_name']);
// set the campaign defaults
$submission->setCampaignDefaults(
$data['campaign_from_name'],
$data['campaign_from_email'],
$data['campaign_subject'],
$data['campaign_language']
);
// set the permission reminder message.
$submission->setPermissionReminder($data['campaign_permission_reminder']);
if (isset($data['admin_email']) && !empty($data['admin_email'])) {
$submission->setNotifyOnSubscribe($data['admin_email']);
$submission->setNotifyOnUnSubscribe($data['admin_email']);
}
$submission->setContact($this->address($data));
try {
$response = $this->api()->createList($submission);
$list_id = array_key_exists('id', $response) ? $response['id'] : false;
$this->setData('errors.mailchimp_list', false);
return $list_id;
} catch (MailChimp_WooCommerce_Error $e) {
$this->setData('errors.mailchimp_list', $e->getMessage());
return false;
}
}
/**
* @param null $data
* @return bool
*/
private function syncStore($data = null)
{
if (empty($data)) {
$data = $this->getOptions();
}
$list_id = $this->array_get($data, 'mailchimp_list', false);
$site_url = $this->getUniqueStoreID();
if (empty($list_id) || empty($site_url)) {
return false;
}
$new = false;
if (!($store = $this->api()->getStore($site_url))) {
$new = true;
$store = new MailChimp_WooCommerce_Store();
}
$call = $new ? 'addStore' : 'updateStore';
$time_key = $new ? 'store_created_at' : 'store_updated_at';
$store->setId($site_url);
$store->setPlatform('woocommerce');
// set the locale data
$store->setPrimaryLocale($this->array_get($data, 'store_locale', 'en'));
$store->setTimezone($this->array_get($data, 'store_timezone', 'America\New_York'));
$store->setCurrencyCode($this->array_get($data, 'store_currency_code', 'USD'));
// set the basics
$store->setName($this->array_get($data, 'store_name'));
$store->setDomain(get_option('siteurl'));
// don't know why we did this before
//$store->setEmailAddress($this->array_get($data, 'campaign_from_email'));
$store->setEmailAddress($this->array_get($data, 'admin_email'));
$store->setAddress($this->address($data));
$store->setPhone($this->array_get($data, 'store_phone'));
$store->setListId($list_id);
try {
// let's create a new store for this user through the API
$this->api()->$call($store);
// apply extra meta for store created at
$this->setData('errors.store_info', false);
$this->setData($time_key, time());
// on a new store push, we need to make sure we save the site script into a local variable.
if ($new) {
mailchimp_update_connected_site_script();
}
return true;
} catch (\Exception $e) {
$this->setData('errors.store_info', $e->getMessage());
}
return false;
}
/**
* @param array $data
* @return MailChimp_WooCommerce_Address
*/
private function address(array $data)
{
$address = new MailChimp_WooCommerce_Address();
if (isset($data['store_street']) && $data['store_street']) {
$address->setAddress1($data['store_street']);
}
if (isset($data['store_city']) && $data['store_city']) {
$address->setCity($data['store_city']);
}
if (isset($data['store_state']) && $data['store_state']) {
$address->setProvince($data['store_state']);
}
if (isset($data['store_country']) && $data['store_country']) {
$address->setCountry($data['store_country']);
}
if (isset($data['store_postal_code']) && $data['store_postal_code']) {
$address->setPostalCode($data['store_postal_code']);
}
if (isset($data['store_name']) && $data['store_name']) {
$address->setCompany($data['store_name']);
}
if (isset($data['store_phone']) && $data['store_phone']) {
$address->setPhone($data['store_phone']);
}
$address->setCountryCode($this->array_get($data, 'store_currency_code', 'USD'));
return $address;
}
/**
* @param array $required
* @param null $options
* @return bool
*/
private function validateOptions(array $required, $options = null)
{
$options = is_array($options) ? $options : $this->getOptions();
foreach ($required as $requirement) {
if (!isset($options[$requirement]) || empty($options[$requirement])) {
return false;
}
}
return true;
}
/**
* Start the sync
*/
private function startSync()
{
mailchimp_flush_sync_pointers();
$coupon_sync = new MailChimp_WooCommerce_Process_Coupons();
wp_queue($coupon_sync);
$job = new MailChimp_WooCommerce_Process_Products();
$job->flagStartSync();
wp_queue($job);
}
/**
* Show the sync started message right when they sync things.
*/
private function showSyncStartedMessage()
{
$text = 'Starting the sync process…
'.
'
Please hang tight while we work our mojo. Sometimes the sync can take a while, '. 'especially on sites with lots of orders and/or products. You may refresh this page at '. 'anytime to check on the progress.
'; add_settings_error('mailchimp-woocommerce_notice', $this->plugin_name, __($text), 'updated'); } }