PluginProbe
Mailchimp List Subscribe Form / 1.5.5
Mailchimp List Subscribe Form v1.5.5
1.2.4 1.2.5 1.2.6 1.2.7 1.2.8 1.2.9 1.3 1.4 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.5 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.5.8 1.5.9 1.6.0 1.6.1 All 55 releases
mailchimp / mailchimp.php

mailchimp.php in Mailchimp List Subscribe Form 1.5.5, at mailchimp.php

1,185 lines 38.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /*
3 Plugin Name: MailChimp
4 Plugin URI: http://www.mailchimp.com/plugins/mailchimp-wordpress-plugin/
5 Description: The MailChimp plugin allows you to quickly and easily add a signup form for your MailChimp list.
6 Version: 1.5.5
7 Author: MailChimp
8 Author URI: https://mailchimp.com/
9 */
10 /* Copyright 2008-2012 MailChimp.com (email : api@mailchimp.com)
11
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; either version 2 of the License, or
15 (at your option) any later version.
16
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
21
22 You should have received a copy of the GNU General Public License
23 along with this program; if not, write to the Free Software
24 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
25 */
26
27 // Version constant for easy CSS refreshes
28 define('MCSF_VER', '1.5.5');
29
30 // What's our permission (capability) threshold
31 define('MCSF_CAP_THRESHOLD', 'manage_options');
32
33 // Define our location constants, both MCSF_DIR and MCSF_URL
34 mailchimpSF_where_am_i();
35
36 // Get our MailChimp API class in scope
37 if (!class_exists('MailChimp_API')) {
38 $path = plugin_dir_path(__FILE__);
39 require_once($path . 'lib/mailchimp/mailchimp.php');
40 }
41
42 // includes the widget code so it can be easily called either normally or via ajax
43 include_once('mailchimp_widget.php');
44
45 // includes the backwards compatibility functions
46 include_once('mailchimp_compat.php');
47
48 /**
49 * Do the following plugin setup steps here
50 *
51 * Internationalization
52 * Resource (JS & CSS) enqueuing
53 *
54 * @return void
55 */
56 function mailchimpSF_plugin_init() {
57 // Internationalize the plugin
58 $textdomain = 'mailchimp_i18n';
59 $locale = apply_filters( 'plugin_locale', get_locale(), $textdomain);
60 load_textdomain('mailchimp_i18n', MCSF_LANG_DIR.$textdomain.'-'.$locale.'.mo');
61
62 // Remove Sopresto check. If user does not have API key, make them authenticate.
63
64 if (get_option('mc_list_id') && get_option('mc_merge_field_migrate') != true && mailchimpSF_get_api() !== false) {
65 mailchimpSF_update_merge_fields(get_option('mc_list_id'));
66 }
67
68 // Bring in our appropriate JS and CSS resources
69 mailchimpSF_load_resources();
70 }
71
72 add_action( 'init', 'mailchimpSF_plugin_init' );
73
74
75 /**
76 * Add the settings link to the MailChimp plugin row
77 *
78 * @param array $links - Links for the plugin
79 * @return array - Links
80 */
81 function mailchimpSD_plugin_action_links($links) {
82 $settings_page = add_query_arg(array('page' => 'mailchimpSF_options'), admin_url('options-general.php'));
83 $settings_link = '<a href="'.esc_url($settings_page).'">'.__('Settings', 'mailchimp_i18n' ).'</a>';
84 array_unshift($links, $settings_link);
85 return $links;
86 }
87 add_filter('plugin_action_links_'.plugin_basename(__FILE__), 'mailchimpSD_plugin_action_links', 10, 1);
88
89 /**
90 * Loads the appropriate JS and CSS resources depending on
91 * settings and context (admin or not)
92 *
93 * @return void
94 */
95 function mailchimpSF_load_resources() {
96 // JS
97 if (get_option('mc_use_javascript') == 'on') {
98 if (!is_admin()) {
99 wp_enqueue_script('jquery_scrollto', MCSF_URL.'js/scrollTo.js', array('jquery'), MCSF_VER);
100 wp_enqueue_script('mailchimpSF_main_js', MCSF_URL.'js/mailchimp.js', array('jquery', 'jquery-form'), MCSF_VER);
101 // some javascript to get ajax version submitting to the proper location
102 global $wp_scripts;
103 $wp_scripts->localize('mailchimpSF_main_js', 'mailchimpSF', array(
104 'ajax_url' => trailingslashit(home_url()),
105 ));
106 }
107 }
108
109 if (get_option('mc_use_datepicker') == 'on' && !is_admin()) {
110 // Datepicker theme
111 wp_enqueue_style('flick', MCSF_URL.'/css/flick/flick.css'
112 );
113 // Datepicker JS
114 wp_enqueue_script('datepicker', MCSF_URL.'/js/datepicker.js', array('jquery','jquery-ui-core'));
115 }
116
117 if(get_option('mc_nuke_all_styles') != true) {
118 wp_enqueue_style('mailchimpSF_main_css', home_url('?mcsf_action=main_css&ver='.MCSF_VER, 'relative'));
119 wp_enqueue_style('mailchimpSF_ie_css', MCSF_URL.'css/ie.css');
120 global $wp_styles;
121 $wp_styles->add_data( 'mailchimpSF_ie_css', 'conditional', 'IE' );
122 }
123 }
124
125
126 /**
127 * Loads resources for the MailChimp admin page
128 *
129 * @return void
130 */
131 function mc_admin_page_load_resources() {
132 wp_enqueue_style('mailchimpSF_admin_css', MCSF_URL.'css/admin.css');
133 }
134 add_action('load-settings_page_mailchimpSF_options', 'mc_admin_page_load_resources');
135
136
137 /**
138 * Loads jQuery Datepicker for the date-pick class
139 **/
140 function mc_datepicker_load() {
141 require_once(MCSF_DIR . '/views/datepicker.php');
142 }
143 if (get_option('mc_use_datepicker') == 'on' && !is_admin()) {
144 add_action('wp_head', 'mc_datepicker_load');
145 }
146
147 /**
148 * Handles requests that as light-weight a load as possible.
149 * typically, JS or CSS
150 **/
151 function mailchimpSF_early_request_handler() {
152 if (isset($_GET['mcsf_action'])) {
153 switch ($_GET['mcsf_action']) {
154 case 'main_css':
155 header("Content-type: text/css");
156 mailchimpSF_main_css();
157 exit;
158 }
159 }
160 }
161 add_action('init', 'mailchimpSF_early_request_handler', 0);
162
163 /**
164 * Outputs the front-end CSS. This checks several options, so it
165 * was best to put it in a Request-handled script, as opposed to
166 * a static file.
167 */
168 function mailchimpSF_main_css() {
169 require_once(MCSF_DIR . '/views/css/frontend.php');
170 }
171
172
173 /**
174 * Add our settings page to the admin menu
175 *
176 * @return void
177 */
178 function mailchimpSF_add_pages(){
179 // Add settings page for users who can edit plugins
180 add_options_page( __( 'MailChimp Setup', 'mailchimp_i18n' ), __( 'MailChimp Setup', 'mailchimp_i18n' ), MCSF_CAP_THRESHOLD, 'mailchimpSF_options', 'mailchimpSF_setup_page');
181 }
182 add_action('admin_menu', 'mailchimpSF_add_pages');
183
184 function mailchimpSF_request_handler() {
185 if (isset($_POST['mcsf_action'])) {
186 switch ($_POST['mcsf_action']) {
187 case 'login':
188 $key = trim($_POST['mailchimpSF_api_key']);
189
190 try {
191 $api = new MailChimp_API($key);
192 } catch (Exception $e) {
193 $msg = "<strong class='mc_error_msg'>" . $e->getMessage() . "</strong>";
194 mailchimpSF_global_msg($msg);
195 break;
196 }
197
198 $key = mailchimpSF_verify_key($api);
199 if(is_wp_error($key)) {
200 $msg = "<strong class='mc_error_msg'>" . $key->get_error_message() . "</strong>";
201 mailchimpSF_global_msg($msg);
202 }
203
204 break;
205 case 'logout':
206 // Check capability & Verify nonce
207 if (!current_user_can(MCSF_CAP_THRESHOLD) || !wp_verify_nonce($_POST['_mcsf_nonce_action'], 'mc_logout')) {
208 wp_die('Cheatin&rsquo; huh?');
209 }
210
211 // erase auth information
212 $options = array('mc_api_key', 'mc_sopresto_user', 'mc_sopresto_public_key', 'mc_sopresto_secret_key');
213 mailchimpSF_delete_options($options);
214 break;
215 case 'change_form_settings':
216 if (!current_user_can(MCSF_CAP_THRESHOLD) || !wp_verify_nonce($_POST['_mcsf_nonce_action'], 'update_general_form_settings')) {
217 wp_die('Cheatin&rsquo; huh?');
218 }
219
220 // Update the form settings
221 mailchimpSF_save_general_form_settings();
222 break;
223 case 'mc_submit_signup_form':
224 // Validate nonce
225 if (!wp_verify_nonce($_POST['_mc_submit_signup_form_nonce'], 'mc_submit_signup_form')) {
226 wp_die('Cheatin&rsquo; huh?');
227 }
228
229 // Attempt the signup
230 mailchimpSF_signup_submit();
231
232 // Do a different action for html vs. js
233 switch ($_POST['mc_submit_type']) {
234 case 'html':
235 /* Allow to fall through. The widget will pick up the
236 * global message left over from the signup_submit function */
237 case 'js':
238 if (!headers_sent()){ //just in case...
239 header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT', true, 200);
240 }
241 echo mailchimpSF_global_msg(); // Don't esc_html this, b/c we've already escaped it
242 exit;
243 }
244 }
245 }
246 }
247 add_action('init', 'mailchimpSF_request_handler');
248
249 function mailchimpSF_migrate_sopresto() {
250 $sopresto = get_option('mc_sopresto_secret_key');
251 if(!$sopresto) {
252 return;
253 }
254
255 // Talk to Sopresto, make exchange, delete old sopresto things.
256 $body = array(
257 'public_key' => get_option('mc_sopresto_public_key'),
258 'hash' => sha1(get_option('mc_sopresto_public_key').get_option('mc_sopresto_secret_key'))
259 );
260
261 $url = 'https://sopresto.socialize-this.com/mailchimp/exchange';
262 $args = array(
263 'method' => 'POST',
264 'timeout' => 500,
265 'redirection' => 5,
266 'httpversion' => '1.0',
267 'user-agent' => 'MailChimp WordPress Plugin/' . get_bloginfo( 'url' ),
268 'body' => $body
269 );
270
271 //post to sopresto
272 $key = wp_remote_post($url, $args);
273 if(!is_wp_error($key) && $key['response']['code'] == 200) {
274 $key = json_decode($key['body']);
275 try {
276 $api = new MailChimp_API($key->response);
277 } catch (Exception $e) {
278 $msg = "<strong class='mc_error_msg'>" . $e->getMessage() . "</strong>";
279 mailchimpSF_global_msg($msg);
280 return;
281 }
282
283 $verify = mailchimpSF_verify_key($api);
284
285 //something went wrong with the key that we had
286 if(is_wp_error($verify)) {
287 return;
288 }
289
290 delete_option('mc_sopresto_public_key');
291 delete_option('mc_sopresto_secret_key');
292 delete_option('mc_sopresto_user');
293
294 return;
295 }
296
297 // Nothing to do here.
298 return;
299 }
300
301 function mailchimpSF_update_merge_fields($list_id)
302 {
303 mailchimpSF_get_merge_vars(get_option('mc_list_id'), true);
304 mailchimpSF_get_interest_categories(get_option('mc_list_id'), true);
305 update_option('mc_merge_field_migrate', true);
306 }
307
308 function mailchimpSF_auth_nonce_key($salt = null) {
309 if (is_null($salt)) {
310 $salt = mailchimpSF_auth_nonce_salt();
311 }
312 return 'social_authentication' . md5( AUTH_KEY . $salt );
313 }
314
315 function mailchimpSF_auth_nonce_salt() {
316 return md5(microtime().$_SERVER['SERVER_ADDR']);
317 }
318
319 /**
320 * Creates new MailChimp API v3 object
321 *
322 * @return MailChimp_API | false
323 */
324
325 function mailchimpSF_get_api($force = false) {
326 $key = get_option('mc_api_key');
327 if($key) {
328 return new MailChimp_API($key);
329 }
330
331 return false;
332 }
333
334
335
336 /**
337 * Checks to see if we're storing a password, if so, we need
338 * to upgrade to the API key
339 *
340 * @return bool
341 **/
342 function mailchimpSF_needs_upgrade() {
343 $igs = get_option('mc_interest_groups');
344
345 if ($igs !== false // we have an option
346 && (
347 empty($igs) || // it can be an empty array (no interest groups)
348 (is_array($igs) && isset($igs[0]['id'])) // OR it should be a populated array that's well-formed
349 )) {
350 return false; // no need to upgrade
351 }
352 else {
353 return true; // yeah, let's do it
354 }
355 }
356
357 /**
358 * Deletes all mailchimp options
359 **/
360 function mailchimpSF_delete_setup() {
361 $options = array('mc_user_id', 'mc_sopresto_user', 'mc_sopresto_public_key', 'mc_sopresto_secret_key', 'mc_rewards', 'mc_use_javascript', 'mc_use_datepicker', 'mc_use_unsub_link', 'mc_list_id', 'mc_list_name', 'mc_interest_groups', 'mc_merge_vars');
362
363 $igs = get_option('mc_interest_groups');
364 if (is_array($igs)) {
365 foreach ($igs as $ig) {
366 $opt = 'mc_show_interest_groups_'.$ig['id'];
367 $options[] = $opt;
368 }
369 }
370
371 $mv = get_option('mc_merge_vars');
372 if (is_array($mv)){
373 foreach($mv as $var){
374 $opt = 'mc_mv_'.$var['tag'];
375 $options[] = $opt;
376 }
377 }
378
379 mailchimpSF_delete_options($options);
380 }
381
382 /**
383 * Gets or sets a global message based on parameter passed to it
384 *
385 * @return string/bool depending on get/set
386 **/
387 function mailchimpSF_global_msg($msg = null) {
388 global $mcsf_msgs;
389
390 // Make sure we're formed properly
391 if (!is_array($mcsf_msgs)) {
392 $mcsf_msgs = array();
393 }
394
395 // See if we're getting
396 if (is_null($msg)) {
397 return implode('', $mcsf_msgs);
398 }
399
400 // Must be setting
401 $mcsf_msgs[] = $msg;
402 return true;
403 }
404
405 /**
406 * Sets the default options for the option form
407 **/
408 function mailchimpSF_set_form_defaults($list_name = '') {
409 update_option('mc_header_content',__( 'Sign up for', 'mailchimp_i18n' ).' '.$list_name);
410 update_option('mc_submit_text',__( 'Subscribe', 'mailchimp_i18n' ));
411
412 update_option('mc_use_datepicker', 'on');
413 update_option('mc_custom_style','off');
414 update_option('mc_use_javascript','on');
415 update_option('mc_double_optin', true);
416 update_option('mc_use_unsub_link','off');
417 update_option('mc_header_border_width','1');
418 update_option('mc_header_border_color','E3E3E3');
419 update_option('mc_header_background','FFFFFF');
420 update_option('mc_header_text_color','CC6600');
421
422 update_option('mc_form_border_width','1');
423 update_option('mc_form_border_color','E0E0E0');
424 update_option('mc_form_background','FFFFFF');
425 update_option('mc_form_text_color','3F3F3f');
426 }
427
428 /**
429 * Saves the General Form settings on the options page
430 *
431 * @return void
432 **/
433 function mailchimpSF_save_general_form_settings() {
434
435 // IF NOT DEV MODE
436 if (isset($_POST['mc_rewards'])){
437 update_option('mc_rewards', 'on');
438 $msg = '<p class="success_msg">'.__('Monkey Rewards turned On!', 'mailchimp_i18n').'</p>';
439 mailchimpSF_global_msg($msg);
440 } else if (get_option('mc_rewards')!='off') {
441 update_option('mc_rewards', 'off');
442 $msg = '<p class="success_msg">'.__('Monkey Rewards turned Off!', 'mailchimp_i18n').'</p>';
443 mailchimpSF_global_msg($msg);
444 }
445 if (isset($_POST['mc_use_javascript'])){
446 update_option('mc_use_javascript', 'on');
447 $msg = '<p class="success_msg">'.__('Fancy Javascript submission turned On!', 'mailchimp_i18n').'</p>';
448 mailchimpSF_global_msg($msg);
449 } else if (get_option('mc_use_javascript')!='off') {
450 update_option('mc_use_javascript', 'off');
451 $msg = '<p class="success_msg">'.__('Fancy Javascript submission turned Off!', 'mailchimp_i18n').'</p>';
452 mailchimpSF_global_msg($msg);
453 }
454
455 if (isset($_POST['mc_use_datepicker'])){
456 update_option('mc_use_datepicker', 'on');
457 $msg = '<p class="success_msg">'.__('Datepicker turned On!', 'mailchimp_i18n').'</p>';
458 mailchimpSF_global_msg($msg);
459 } else if (get_option('mc_use_datepicker')!='off') {
460 update_option('mc_use_datepicker', 'off');
461 $msg = '<p class="success_msg">'.__('Datepicker turned Off!', 'mailchimp_i18n').'</p>';
462 mailchimpSF_global_msg($msg);
463 }
464
465 /*Enable double optin toggle*/
466
467 if(isset($_POST['mc_double_optin'])) {
468 update_option('mc_double_optin', true);
469 $msg = '<p class="success_msg">'.__('Double opt-in turned On!', 'mailchimp_i18n').'</p>';
470 mailchimpSF_global_msg($msg);
471 } else if (get_option('mc_double_optin') != false) {
472 update_option('mc_double_optin', false);
473 $msg = '<p class="success_msg">'.__('Double opt-in turned Off!', 'mailchimp_i18n').'</p>';
474 mailchimpSF_global_msg($msg);
475 }
476
477 /* NUKE the CSS! */
478 if(isset($_POST['mc_nuke_all_styles'])) {
479 update_option('mc_nuke_all_styles', true);
480 $msg = '<p class="success_msg">'.__('MailChimp CSS turned Off!', 'mailchimp_i18n').'</p>';
481 mailchimpSF_global_msg($msg);
482 }elseif (get_option('mc_nuke_all_styles') !== false) {
483 update_option('mc_nuke_all_styles', false);
484 $msg = '<p class="success_msg">'.__('MailChimp CSS turned On!', 'mailchimp_i18n').'</p>';
485 mailchimpSF_global_msg($msg);
486 }
487
488 /* Update existing */
489 if (isset($_POST['mc_update_existing'])) {
490 update_option('mc_update_existing', true);
491 $msg = '<p class="success_msg">' . __('Update existing subscribers turned On!') . '</p>';
492 mailchimpSF_global_msg($msg);
493 } elseif (get_option('mc_update_existing') ==! false) {
494 update_option('mc_update_existing', false);
495 $msg = '<p class="success_msg">' . __('Update existing subscribers turned Off!') . '</p>';
496 mailchimpSF_global_msg($msg);
497 }
498
499 if (isset($_POST['mc_use_unsub_link'])){
500 update_option('mc_use_unsub_link', 'on');
501 $msg = '<p class="success_msg">'.__('Unsubscribe link turned On!', 'mailchimp_i18n').'</p>';
502 mailchimpSF_global_msg($msg);
503 }
504
505 elseif (get_option('mc_use_unsub_link')!='off') {
506 update_option('mc_use_unsub_link', 'off');
507 $msg = '<p class="success_msg">'.__('Unsubscribe link turned Off!', 'mailchimp_i18n').'</p>';
508 mailchimpSF_global_msg($msg);
509 }
510
511 $content = stripslashes($_POST['mc_header_content']);
512 $content = str_replace("\r\n","<br/>", $content);
513 update_option('mc_header_content', $content );
514
515 $content = stripslashes($_POST['mc_subheader_content']);
516 $content = str_replace("\r\n","<br/>", $content);
517 update_option('mc_subheader_content', $content );
518
519
520 $submit_text = stripslashes($_POST['mc_submit_text']);
521 $submit_text = str_replace("\r\n","", $submit_text);
522 update_option('mc_submit_text', $submit_text);
523
524 // Set Custom Style option
525 update_option('mc_custom_style', isset($_POST['mc_custom_style']) ? 'on' : 'off');
526
527 //we told them not to put these things we are replacing in, but let's just make sure they are listening...
528 if(isset($_POST['mc_form_border_width'])) {
529 update_option('mc_form_border_width',str_replace('px', '', $_POST['mc_form_border_width']) );
530 }
531 if(isset($_POST['mc_form_border_color'])) {
532 update_option('mc_form_border_color', str_replace('#', '', $_POST['mc_form_border_color']));
533 }
534 if(isset($_POST['mc_form_background'])){
535 update_option('mc_form_background',str_replace('#', '', $_POST['mc_form_background']));
536 }
537 if(isset($_POST['mc_form_text_color'])) {
538 update_option('mc_form_text_color', str_replace('#', '', $_POST['mc_form_text_color']));
539 }
540
541
542 // IF NOT DEV MODE
543 $igs = get_option('mc_interest_groups');
544 if (is_array($igs)) {
545 foreach($igs as $var){
546 $opt = 'mc_show_interest_groups_'.$var['id'];
547 if (isset($_POST[$opt])){
548 update_option($opt,'on');
549 } else {
550 update_option($opt,'off');
551 }
552 }
553 }
554
555 $mv = get_option('mc_merge_vars');
556 if (is_array($mv)) {
557 foreach($mv as $var){
558 $opt = 'mc_mv_'.$var['tag'];
559 if (isset($_POST[$opt]) || $var['required']=='Y'){
560 update_option($opt,'on');
561 } else {
562 update_option($opt,'off');
563 }
564 }
565 }
566
567 $msg = '<p class="success_msg">'.esc_html(__('Successfully Updated your List Subscribe Form Settings!', 'mailchimp_i18n')).'</p>';
568 mailchimpSF_global_msg($msg);
569 }
570
571 /**
572 * Sees if the user changed the list, and updates options accordingly
573 **/
574 function mailchimpSF_change_list_if_necessary() {
575 // Simple permission check before going through all this
576 if (!current_user_can(MCSF_CAP_THRESHOLD)) { return; }
577
578 $api = mailchimpSF_get_api();
579 if (!$api) { return; }
580
581 //we *could* support paging, but few users have that many lists (and shouldn't)
582 $lists = $api->get('lists',100, array('fields' => 'lists.id,lists.name,lists.email_type_option'));
583 $lists = $lists['lists'];
584
585 if (is_array($lists) && !empty($lists) && isset($_POST['mc_list_id'])) {
586
587 /* If our incoming list ID (the one chosen in the select dropdown)
588 is in our array of lists, the set it to be the active list */
589 foreach($lists as $key => $list) {
590 if ($list['id'] == $_POST['mc_list_id']) {
591 $list_id = $_POST['mc_list_id'];
592 $list_name = $list['name'];
593 $list_key = $key;
594 }
595 }
596
597 $orig_list = get_option('mc_list_id');
598 if ($list_id != '') {
599 update_option('mc_list_id', $list_id);
600 update_option('mc_list_name', $list_name);
601 update_option('mc_email_type_option', $lists[$list_key]['email_type_option']);
602
603
604 // See if the user changed the list
605 $new_list = false;
606 if ($orig_list != $list_id){
607 // The user changed the list, Reset the Form Defaults
608 mailchimpSF_set_form_defaults($list_name);
609
610 $new_list = true;
611 }
612 // email_type_option
613
614 // Grab the merge vars and interest groups
615 $mv = mailchimpSF_get_merge_vars($list_id, $new_list);
616 $igs = mailchimpSF_get_interest_categories($list_id, $new_list);
617
618 $igs_text = ' ';
619 if (is_array($igs)) {
620 $igs_text .= sprintf(__('and %s Sets of Interest Groups', 'mailchimp_i18n'), count($igs));
621 }
622
623 $msg = '<p class="success_msg">'.
624 sprintf(
625 __('<b>Success!</b> Loaded and saved the info for %d Merge Variables', 'mailchimp_i18n').$igs_text,
626 count($mv)
627 ).' '.
628 __('from your list').' "'.$list_name.'"<br/><br/>'.
629 __('Now you should either Turn On the MailChimp Widget or change your options below, then turn it on.', 'mailchimp_i18n').'</p>';
630 mailchimpSF_global_msg($msg);
631 }
632 }
633 }
634
635 function mailchimpSF_get_merge_vars($list_id, $new_list) {
636 $api = mailchimpSF_get_api();
637 $mv = $api->get('lists/' . $list_id . '/merge-fields', 80);
638
639 //if we get an error back from the api, exit this process.
640 if(is_wp_error($mv)) {
641 return;
642 }
643
644 $mv['merge_fields'] = mailchimpSF_add_email_field($mv['merge_fields']);
645 update_option('mc_merge_vars', $mv['merge_fields']);
646 foreach($mv['merge_fields'] as $var){
647 $opt = 'mc_mv_'.$var['tag'];
648 //turn them all on by default
649 if ($new_list) {
650 update_option($opt, 'on' );
651 }
652 }
653 return $mv['merge_fields'];
654 }
655
656 function mailchimpSF_add_email_field($merge) {
657
658 $email = array(
659 'tag' => 'EMAIL',
660 'name' => __('Email Address', 'mailchimp_i18n'),
661 'type' => 'email',
662 'required' => true,
663 'public' => true,
664 'display_order' => 1,
665 'default_value' => null
666 );
667 array_unshift($merge, $email);
668 return $merge;
669 }
670
671 function mailchimpSF_get_interest_categories($list_id, $new_list) {
672 $api = mailchimpSF_get_api();
673 $igs = $api->get('lists/' . $list_id . '/interest-categories', 60);
674
675 //if we get an error back from the api, exis
676 if(is_wp_error($igs)) {
677 return;
678 }
679
680 if (is_array($igs)) {
681 $key = 0;
682 foreach($igs['categories'] as $ig) {
683 $groups = $api->get('lists/' . $list_id . '/interest-categories/' . $ig['id'] . '/interests', 60);
684 $igs['categories'][$key]['groups'] = $groups['interests'];
685 $opt = 'mc_show_interest_groups_'.$ig['id'];
686
687 //turn them all on by default
688 if ($new_list) {
689 update_option($opt, 'on' );
690 }
691 $key++;
692 }
693 }
694 update_option('mc_interest_groups', $igs['categories']);
695 return $igs['categories'];
696 }
697
698
699 /**
700 * Outputs the Settings/Options page
701 */
702 function mailchimpSF_setup_page() {
703 $path = plugin_dir_path(__FILE__);
704 wp_enqueue_script('showMe', MCSF_URL.'js/hidecss.js', array('jquery'), MCSF_VER);
705 require_once($path.'/views/setup_page.php');
706 }//mailchimpSF_setup_page()
707
708
709 function mailchimpSF_register_widgets() {
710 if (mailchimpSF_get_api()) {
711 register_widget('mailchimpSF_Widget');
712 }
713 }
714 add_action('widgets_init', 'mailchimpSF_register_widgets');
715
716 function mailchimpSF_shortcode($atts){
717 ob_start();
718 mailchimpSF_signup_form();
719 return ob_get_clean();
720 }
721 add_shortcode('mailchimpsf_form', 'mailchimpSF_shortcode');
722
723 /**
724 * Attempts to signup a user, per the $_POST args.
725 *
726 * This sets a global message, that is then used in the widget
727 * output to retrieve and display that message.
728 *
729 * @return bool
730 */
731 function mailchimpSF_signup_submit() {
732 $mv = get_option('mc_merge_vars', array());
733 $mv_tag_keys = array();
734
735 $igs = get_option('mc_interest_groups', array());
736
737 $listId = get_option('mc_list_id');
738 $email = isset($_POST['mc_mv_EMAIL']) ? strip_tags(stripslashes($_POST['mc_mv_EMAIL'])) : '';
739 $merge = $errs = $html_errs = array(); // Set up some vars
740
741 $merge = mailchimpSF_merge_submit($mv);
742
743 //Catch errors and fail early.
744 if(is_wp_error($merge)) {
745 $msg = "<strong class='mc_error_msg'>" . $merge->get_error_message() . "</strong>";
746 mailchimpSF_global_msg($msg);
747
748 return false;
749 }
750
751 // Head back to the beginning of the merge vars array
752 reset($mv);
753 // Ensure we have an array
754 $igs = !is_array($igs) ? array() : $igs;
755 $igs = mailchimpSF_groups_submit($igs);
756
757 // Clear out empty merge vars
758 $merge = mailchimpSF_merge_remove_empty($merge);
759 if (isset($_POST['email_type']) && in_array($_POST['email_type'], array('text', 'html', 'mobile'))) {
760 $email_type = $_POST['email_type'];
761 }
762 else {
763 $email_type = 'html';
764 }
765
766 $api = mailchimpSF_get_api();
767 if (!$api) {
768 $url = mailchimpSF_signup_form_url();
769 $error = '<strong class="mc_error_msg">'. __('We encountered a problem adding ' . $email . ' to the list. Please <a href="' . $url . '">sign up here.</a>') . '</strong>';
770 mailchimpSF_global_msg($error);
771 return false;
772 }
773
774 $url = 'lists/'. $listId . '/members/' . md5(strtolower($email));
775 $status = mailchimpSF_check_status($url);
776
777
778 // If update existing is turned off and the subscriber exists, error out.
779 if (get_option('mc_update_existing') == false && $status === 'subscribed') {
780 $msg = 'This email address is already subscribed to the list.';
781 $error = new WP_Error('mailchimp-update-existing', $msg);
782 mailchimpSF_global_msg('<strong class="mc_error_msg">' . $msg . '</strong>');
783 return false;
784 }
785
786 $body = mailchimpSF_subscribe_body($merge, $igs, $email_type, $email, $status, get_option('mc_double_optin'));
787 $retval = $api->post($url, $body, 'PUT');
788
789 // If we have errors, then show them
790 if(is_wp_error($retval)) {
791 $msg = "<strong class='mc_error_msg'>" . $retval->get_error_message() . "</strong>";
792 mailchimpSF_global_msg($msg);
793 return false;
794 }
795
796 if($retval['status'] == 'subscribed') {
797 $esc = __("Success, you've been signed up.", 'mailchimp_i18n');
798 $msg = "<strong class='mc_success_msg'>{$esc}</strong>";
799 } else {
800 $esc = __("Success, you've been signed up! Please look for our confirmation email.", 'mailchimp_i18n');
801 $msg = "<strong class='mc_success_msg'>{$esc}</strong>";
802 }
803
804 // Set our global message
805 mailchimpSF_global_msg($msg);
806
807 return true;
808 }
809
810 /*
811 Cleans up merge fields and interests to make them
812 API 3.0-friendly.
813 */
814
815 function mailchimpSF_subscribe_body($merge, $igs, $email_type, $email, $status, $double_optin)
816 {
817 $body = new stdClass();
818 $body->email_address = $email;
819 $body->email_type = $email_type;
820 $body->merge_fields = $merge;
821 if (!empty($igs)) {
822 $body->interests = $igs;
823 }
824
825 if($status !== 'subscribed') {
826 // single opt-in that covers new subscribers
827 if (!$status && $double_optin == false) {
828 $body->status = 'subscribed';
829 } else {
830 // anyone else
831 $body->status = 'pending';
832 }
833 }
834 return $body;
835 }
836
837 function mailchimpSF_check_status($endpoint) {
838 $endpoint .= '?fields=status';
839 $api = mailchimpSF_get_api();
840 $subscriber = $api->get($endpoint, null);
841 if(is_wp_error($subscriber)) {
842 return false;
843 }
844 return $subscriber['status'];
845 }
846
847 function mailchimpSF_merge_submit($mv) {
848 // Loop through our Merge Vars, and if they're empty, but required, then print an error, and mark as failed
849 $merge = new stdClass();
850 foreach($mv as $var) {
851 // We also want to create an array where the keys are the tags for easier validation later
852 $tag = $var['tag'];
853 $mv_tag_keys[$tag] = $var;
854
855 $opt = 'mc_mv_' . $tag;
856
857 $opt_val = isset($_POST[$opt]) ? stripslashes_deep($_POST[$opt]) : '';
858
859 // Handle phone number logic
860 if ($var['type'] === 'phone' && $var['options']['phone_format'] === 'US') {
861 $opt_val = mailchimpSF_merge_validate_phone($opt_val, $var);
862 if(is_wp_error($opt_val)) {
863 return $opt_val;
864 }
865 }
866 // Handle address logic
867 else if (is_array($opt_val) && $var['type'] == 'address') {
868 $validate = mailchimpSF_merge_validate_address($opt_val, $var);
869 if(is_wp_error($validate)) {
870 return $validate;
871 }
872
873 if($validate) {
874 $merge->$tag = $validate;
875 }
876 continue;
877
878 }
879 else if (is_array($opt_val)) {
880 $keys = array_keys($opt_val);
881 $val = new stdClass();
882 foreach($keys as $key) {
883 $val->$key = $opt_val[$key];
884 }
885 $opt_val = $val;
886 }
887
888 if ($var['required'] == 'Y' && trim($opt_val) == '') {
889 $message = sprintf(__("You must fill in %s.", 'mailchimp_i18n'), esc_html($var['name']));
890 $error = new WP_Error('missing_required_field', $message);
891 return $error;
892 }
893 else {
894 if ($tag != 'EMAIL') {
895 $merge->$tag = $opt_val;
896 }
897 }
898 }
899 return $merge;
900 }
901
902 function mailchimpSF_merge_validate_phone($opt_val, $var) {
903 // This filters out all 'falsey' elements
904 $opt_val = array_filter($opt_val);
905 // If they weren't all empty
906 if (!$opt_val) {
907 return;
908 }
909
910 $opt_val = implode('-', $opt_val);
911 if (strlen($opt_val) < 12) {
912 $opt_val = '';
913 }
914
915
916 if (!preg_match('/[0-9]{0,3}-[0-9]{0,3}-[0-9]{0,4}/A', $opt_val)) {
917 $message = sprintf(__("%s must consist of only numbers", 'mailchimp_i18n'), esc_html($var['name']));
918 $error = new WP_Error('mc_phone_validation', $message);
919 return $error;
920 }
921
922 return $opt_val;
923 }
924
925 function mailchimpSF_merge_validate_address($opt_val, $var) {
926 if ($var['required'] == 'Y') {
927 if (empty($opt_val['addr1']) || empty($opt_val['city'])) {
928 $message = sprintf(__("You must fill in %s.", 'mailchimp_i18n'), esc_html($var['name']));
929 $error = new WP_Error('invalid_address_merge', $message);
930 return $error;
931 }
932 } else {
933 if (empty($opt_val['addr1']) || empty($opt_val['city'])) {
934 return false;
935 }
936 }
937
938 $merge = new stdClass();
939 $merge->addr1 = $opt_val['addr1'];
940 $merge->addr2 = $opt_val['addr2'];
941 $merge->city = $opt_val['city'];
942 $merge->state = $opt_val['state'];
943 $merge->zip = $opt_val['zip'];
944 $merge->country = $opt_val['country'];
945 return $merge;
946
947 }
948
949 function mailchimpSF_merge_remove_empty($merge)
950 {
951 foreach ($merge as $k => $v) {
952 if (is_object($v) && empty($v)) {
953 unset($merge->$k);
954 } elseif ((is_string($v) && trim($v) === '') || is_null($v)) {
955 unset($merge->$k);
956 }
957 }
958
959 // If we have an empty $merge, then assign empty string.
960 if (count($merge) == 0 || $merge == '') {
961 $merge = '';
962 }
963
964 return $merge;
965 }
966
967 function mailchimpSF_groups_submit($igs) {
968 $groups = mailchimpSF_set_all_groups_to_false();
969
970 if(empty($igs)) {
971 return new StdClass();
972 }
973
974 //get groups and ids
975 //set all to false
976
977 foreach ($igs as $ig) {
978 $ig_id = $ig['id'];
979 if (get_option('mc_show_interest_groups_'.$ig_id) == 'on' && $ig['type'] !== 'hidden') {
980 switch ($ig['type']) {
981 case 'dropdown':
982 case 'radio':
983 // there can only be one value submitted for radio/dropdowns, so use that at the group id.
984 if (isset($_POST['group'][$ig_id]) && !empty($_POST['group'][$ig_id])) {
985 $value = $_POST['group'][$ig_id];
986 $groups->$value = true;
987 }
988 break;
989 case 'checkboxes':
990 if (isset($_POST['group'][$ig_id])) {
991 foreach ($_POST['group'][$ig_id] as $id => $value) {
992 $groups->$id = true;
993 }
994 }
995 break;
996 default:
997 // Nothing
998 break;
999 }
1000 }
1001 }
1002 return $groups;
1003 }
1004
1005 function mailchimpSF_set_all_groups_to_false() {
1006 $toreturn = new StdClass();
1007
1008 foreach (get_option('mc_interest_groups') as $grouping) {
1009 if($grouping['type'] !== 'hidden') {
1010 foreach ($grouping['groups'] as $group) {
1011 $id = $group['id'];
1012 $toreturn->$id = false;
1013 }
1014 }
1015 }
1016
1017 return $toreturn;
1018 }
1019
1020 function mailchimpSF_verify_key($api) {
1021 $user = $api->get('');
1022 if (is_wp_error($user)) {
1023 return $user;
1024 }
1025
1026 //Might as well set this data if we have it already.
1027 $valid_roles = array('owner', 'admin', 'manager');
1028 if(in_array($user['role'], $valid_roles)) {
1029 update_option('mc_api_key', $api->key);
1030 update_option('mc_user', $user);
1031 update_option('mc_datacenter', $api->datacenter);
1032
1033 } else {
1034 $msg = __('API Key must belong to "Owner", "Admin", or "Manager."', 'mailchimp_i18n');
1035 return new WP_Error('mc-invalid-role', $msg);
1036 }
1037 return;
1038 }
1039
1040 function mailchimpSF_update_profile_url($email) {
1041 $dc = get_option('mc_datacenter');
1042 $eid = base64_encode($email);
1043 $user = get_option('mc_user');
1044 $list_id = get_option('mc_list_id');
1045 $url = 'http://' . $dc . '.list-manage.com/subscribe/send-email?u=' . $user['account_id'] . '&id=' . $list_id . '&e=' . $eid;
1046 return $url;
1047 }
1048
1049 function mailchimpSF_signup_form_url() {
1050 $dc = get_option('mc_datacenter');
1051 $user = get_option('mc_user');
1052 $list_id = get_option('mc_list_id');
1053 $url = 'http://' . $dc . '.list-manage.com/subscribe?u=' . $user['account_id'] . '&id=' . $list_id;
1054 return $url;
1055 }
1056
1057 function mailchimpSF_delete_options($options = array()) {
1058 foreach($options as $option) {
1059 delete_option($option);
1060 }
1061 }
1062
1063
1064 /**********************
1065 * Utility Functions *
1066 **********************/
1067 /**
1068 * Utility function to allow placement of plugin in plugins, mu-plugins, child or parent theme's plugins folders
1069 *
1070 * This function must be ran _very early_ in the load process, as it sets up important constants for the rest of the plugin
1071 */
1072 function mailchimpSF_where_am_i() {
1073 $locations = array(
1074 'plugins' => array(
1075 'dir' => plugin_dir_path(__FILE__),
1076 'url' => plugins_url()
1077 ),
1078 'mu_plugins' => array(
1079 'dir' => plugin_dir_path(__FILE__),
1080 'url' => plugins_url(),
1081 ),
1082 'template' => array(
1083 'dir' => trailingslashit(get_template_directory()).'plugins/',
1084 'url' => trailingslashit(get_template_directory_uri()).'plugins/',
1085 ),
1086 'stylesheet' => array(
1087 'dir' => trailingslashit(get_stylesheet_directory()).'plugins/',
1088 'url' => trailingslashit(get_stylesheet_directory_uri()).'plugins/',
1089 ),
1090 );
1091
1092 // Set defaults
1093 $mscf_dirbase = trailingslashit(basename(dirname(__FILE__))); // Typically wp-mailchimp/ or mailchimp/
1094 $mscf_dir = trailingslashit(plugin_dir_path(__FILE__));
1095 $mscf_url = trailingslashit(plugins_url(null, __FILE__));
1096
1097 // Try our hands at finding the real location
1098 foreach ($locations as $key => $loc) {
1099 $dir = trailingslashit($loc['dir']).$mscf_dirbase;
1100 $url = trailingslashit($loc['url']).$mscf_dirbase;
1101 if (is_file($dir.basename(__FILE__))) {
1102 $mscf_dir = $dir;
1103 $mscf_url = $url;
1104 break;
1105 }
1106 }
1107
1108 // Define our complete filesystem path
1109 define('MCSF_DIR', $mscf_dir);
1110
1111 /* Lang location needs to be relative *from* ABSPATH,
1112 so strip it out of our language dir location */
1113 define('MCSF_LANG_DIR', trailingslashit(MCSF_DIR).'po/');
1114
1115 // Define our complete URL to the plugin folder
1116 define('MCSF_URL', $mscf_url);
1117 }
1118
1119
1120 /**
1121 * MODIFIED VERSION of wp_verify_nonce from WP Core. Core was not overridden to prevent problems when replacing
1122 * something universally.
1123 *
1124 * Verify that correct nonce was used with time limit.
1125 *
1126 * The user is given an amount of time to use the token, so therefore, since the
1127 * UID and $action remain the same, the independent variable is the time.
1128 *
1129 * @param string $nonce Nonce that was used in the form to verify
1130 * @param string|int $action Should give context to what is taking place and be the same when nonce was created.
1131 * @return bool Whether the nonce check passed or failed.
1132 */
1133 function mailchimpSF_verify_nonce($nonce, $action = -1) {
1134 $user = wp_get_current_user();
1135 $uid = (int) $user->ID;
1136 if ( ! $uid ) {
1137 $uid = apply_filters( 'nonce_user_logged_out', $uid, $action );
1138 }
1139
1140 if ( empty( $nonce ) ) {
1141 return false;
1142 }
1143
1144 $token = 'MAILCHIMP';
1145 $i = wp_nonce_tick();
1146
1147 // Nonce generated 0-12 hours ago
1148 $expected = substr( wp_hash( $i . '|' . $action . '|' . $uid . '|' . $token, 'nonce'), -12, 10 );
1149 if ( hash_equals( $expected, $nonce ) ) {
1150 return 1;
1151 }
1152
1153 // Nonce generated 12-24 hours ago
1154 $expected = substr( wp_hash( ( $i - 1 ) . '|' . $action . '|' . $uid . '|' . $token, 'nonce' ), -12, 10 );
1155 if ( hash_equals( $expected, $nonce ) ) {
1156 return 2;
1157 }
1158
1159 // Invalid nonce
1160 return false;
1161 }
1162
1163
1164 /**
1165 * MODIFIED VERSION of wp_create_nonce from WP Core. Core was not overridden to prevent problems when replacing
1166 * something universally.
1167 *
1168 * Creates a cryptographic token tied to a specific action, user, and window of time.
1169 *
1170 * @param string $action Scalar value to add context to the nonce.
1171 * @return string The token.
1172 */
1173 function mailchimpSF_create_nonce($action = -1) {
1174 $user = wp_get_current_user();
1175 $uid = (int) $user->ID;
1176 if ( ! $uid ) {
1177 /** This filter is documented in wp-includes/pluggable.php */
1178 $uid = apply_filters( 'nonce_user_logged_out', $uid, $action );
1179 }
1180
1181 $token = 'MAILCHIMP';
1182 $i = wp_nonce_tick();
1183
1184 return substr( wp_hash( $i . '|' . $action . '|' . $uid . '|' . $token, 'nonce' ), -12, 10 );
1185 }