PluginProbe
Mailchimp List Subscribe Form / 1.5.7
Mailchimp List Subscribe Form v1.5.7
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.7, at mailchimp.php

1,186 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.7
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.7');
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 /* This gets set elsewhere! */
236 break;
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
584 $lists = $lists['lists'];
585
586 if (is_array($lists) && !empty($lists) && isset($_POST['mc_list_id'])) {
587
588 /* If our incoming list ID (the one chosen in the select dropdown)
589 is in our array of lists, the set it to be the active list */
590 foreach($lists as $key => $list) {
591 if ($list['id'] == $_POST['mc_list_id']) {
592 $list_id = $_POST['mc_list_id'];
593 $list_name = $list['name'];
594 $list_key = $key;
595 }
596 }
597
598 $orig_list = get_option('mc_list_id');
599 if ($list_id != '') {
600 update_option('mc_list_id', $list_id);
601 update_option('mc_list_name', $list_name);
602 update_option('mc_email_type_option', $lists[$list_key]['email_type_option']);
603
604
605 // See if the user changed the list
606 $new_list = false;
607 if ($orig_list != $list_id){
608 // The user changed the list, Reset the Form Defaults
609 mailchimpSF_set_form_defaults($list_name);
610
611 $new_list = true;
612 }
613 // email_type_option
614
615 // Grab the merge vars and interest groups
616 $mv = mailchimpSF_get_merge_vars($list_id, $new_list);
617 $igs = mailchimpSF_get_interest_categories($list_id, $new_list);
618
619 $igs_text = ' ';
620 if (is_array($igs)) {
621 $igs_text .= sprintf(__('and %s Sets of Interest Groups', 'mailchimp_i18n'), count($igs));
622 }
623
624 $msg = '<p class="success_msg">'.
625 sprintf(
626 __('<b>Success!</b> Loaded and saved the info for %d Merge Variables', 'mailchimp_i18n').$igs_text,
627 count($mv)
628 ).' '.
629 __('from your list').' "'.$list_name.'"<br/><br/>'.
630 __('Now you should either Turn On the MailChimp Widget or change your options below, then turn it on.', 'mailchimp_i18n').'</p>';
631 mailchimpSF_global_msg($msg);
632 }
633 }
634 }
635
636 function mailchimpSF_get_merge_vars($list_id, $new_list) {
637 $api = mailchimpSF_get_api();
638 $mv = $api->get('lists/' . $list_id . '/merge-fields', 80);
639
640 //if we get an error back from the api, exit this process.
641 if(is_wp_error($mv)) {
642 return;
643 }
644
645 $mv['merge_fields'] = mailchimpSF_add_email_field($mv['merge_fields']);
646 update_option('mc_merge_vars', $mv['merge_fields']);
647 foreach($mv['merge_fields'] as $var){
648 $opt = 'mc_mv_'.$var['tag'];
649 //turn them all on by default
650 if ($new_list) {
651 update_option($opt, 'on' );
652 }
653 }
654 return $mv['merge_fields'];
655 }
656
657 function mailchimpSF_add_email_field($merge) {
658
659 $email = array(
660 'tag' => 'EMAIL',
661 'name' => __('Email Address', 'mailchimp_i18n'),
662 'type' => 'email',
663 'required' => true,
664 'public' => true,
665 'display_order' => 1,
666 'default_value' => null
667 );
668 array_unshift($merge, $email);
669 return $merge;
670 }
671
672 function mailchimpSF_get_interest_categories($list_id, $new_list) {
673 $api = mailchimpSF_get_api();
674 $igs = $api->get('lists/' . $list_id . '/interest-categories', 60);
675
676 //if we get an error back from the api, exis
677 if(is_wp_error($igs)) {
678 return;
679 }
680
681 if (is_array($igs)) {
682 $key = 0;
683 foreach($igs['categories'] as $ig) {
684 $groups = $api->get('lists/' . $list_id . '/interest-categories/' . $ig['id'] . '/interests', 60);
685 $igs['categories'][$key]['groups'] = $groups['interests'];
686 $opt = 'mc_show_interest_groups_'.$ig['id'];
687
688 //turn them all on by default
689 if ($new_list) {
690 update_option($opt, 'on' );
691 }
692 $key++;
693 }
694 }
695 update_option('mc_interest_groups', $igs['categories']);
696 return $igs['categories'];
697 }
698
699
700 /**
701 * Outputs the Settings/Options page
702 */
703 function mailchimpSF_setup_page() {
704 $path = plugin_dir_path(__FILE__);
705 wp_enqueue_script('showMe', MCSF_URL.'js/hidecss.js', array('jquery'), MCSF_VER);
706 require_once($path.'/views/setup_page.php');
707 }//mailchimpSF_setup_page()
708
709
710 function mailchimpSF_register_widgets() {
711 if (mailchimpSF_get_api()) {
712 register_widget('mailchimpSF_Widget');
713 }
714 }
715 add_action('widgets_init', 'mailchimpSF_register_widgets');
716
717 function mailchimpSF_shortcode($atts){
718 ob_start();
719 mailchimpSF_signup_form();
720 return ob_get_clean();
721 }
722 add_shortcode('mailchimpsf_form', 'mailchimpSF_shortcode');
723
724 /**
725 * Attempts to signup a user, per the $_POST args.
726 *
727 * This sets a global message, that is then used in the widget
728 * output to retrieve and display that message.
729 *
730 * @return bool
731 */
732 function mailchimpSF_signup_submit() {
733 $mv = get_option('mc_merge_vars', array());
734 $mv_tag_keys = array();
735
736 $igs = get_option('mc_interest_groups', array());
737
738 $listId = get_option('mc_list_id');
739 $email = isset($_POST['mc_mv_EMAIL']) ? strip_tags(stripslashes($_POST['mc_mv_EMAIL'])) : '';
740 $merge = $errs = $html_errs = array(); // Set up some vars
741
742 $merge = mailchimpSF_merge_submit($mv);
743
744 //Catch errors and fail early.
745 if(is_wp_error($merge)) {
746 $msg = "<strong class='mc_error_msg'>" . $merge->get_error_message() . "</strong>";
747 mailchimpSF_global_msg($msg);
748
749 return false;
750 }
751
752 // Head back to the beginning of the merge vars array
753 reset($mv);
754 // Ensure we have an array
755 $igs = !is_array($igs) ? array() : $igs;
756 $igs = mailchimpSF_groups_submit($igs);
757
758 // Clear out empty merge vars
759 $merge = mailchimpSF_merge_remove_empty($merge);
760 if (isset($_POST['email_type']) && in_array($_POST['email_type'], array('text', 'html', 'mobile'))) {
761 $email_type = $_POST['email_type'];
762 }
763 else {
764 $email_type = 'html';
765 }
766
767 $api = mailchimpSF_get_api();
768 if (!$api) {
769 $url = mailchimpSF_signup_form_url();
770 $error = '<strong class="mc_error_msg">'. __('We encountered a problem adding ' . $email . ' to the list. Please <a href="' . $url . '">sign up here.</a>') . '</strong>';
771 mailchimpSF_global_msg($error);
772 return false;
773 }
774
775 $url = 'lists/'. $listId . '/members/' . md5(strtolower($email));
776 $status = mailchimpSF_check_status($url);
777
778
779 // If update existing is turned off and the subscriber exists, error out.
780 if (get_option('mc_update_existing') == false && $status === 'subscribed') {
781 $msg = 'This email address is already subscribed to the list.';
782 $error = new WP_Error('mailchimp-update-existing', $msg);
783 mailchimpSF_global_msg('<strong class="mc_error_msg">' . $msg . '</strong>');
784 return false;
785 }
786
787 $body = mailchimpSF_subscribe_body($merge, $igs, $email_type, $email, $status, get_option('mc_double_optin'));
788 $retval = $api->post($url, $body, 'PUT');
789
790 // If we have errors, then show them
791 if(is_wp_error($retval)) {
792 $msg = "<strong class='mc_error_msg'>" . $retval->get_error_message() . "</strong>";
793 mailchimpSF_global_msg($msg);
794 return false;
795 }
796
797 if($retval['status'] == 'subscribed') {
798 $esc = __("Success, you've been signed up.", 'mailchimp_i18n');
799 $msg = "<strong class='mc_success_msg'>{$esc}</strong>";
800 } else {
801 $esc = __("Success, you've been signed up! Please look for our confirmation email.", 'mailchimp_i18n');
802 $msg = "<strong class='mc_success_msg'>{$esc}</strong>";
803 }
804
805 // Set our global message
806 mailchimpSF_global_msg($msg);
807
808 return true;
809 }
810
811 /*
812 Cleans up merge fields and interests to make them
813 API 3.0-friendly.
814 */
815
816 function mailchimpSF_subscribe_body($merge, $igs, $email_type, $email, $status, $double_optin)
817 {
818 $body = new stdClass();
819 $body->email_address = $email;
820 $body->email_type = $email_type;
821 $body->merge_fields = $merge;
822 if (!empty($igs)) {
823 $body->interests = $igs;
824 }
825
826 if($status !== 'subscribed') {
827 // single opt-in that covers new subscribers
828 if (!$status && $double_optin == false) {
829 $body->status = 'subscribed';
830 } else {
831 // anyone else
832 $body->status = 'pending';
833 }
834 }
835 return $body;
836 }
837
838 function mailchimpSF_check_status($endpoint) {
839 $endpoint .= '?fields=status';
840 $api = mailchimpSF_get_api();
841 $subscriber = $api->get($endpoint, null);
842 if(is_wp_error($subscriber)) {
843 return false;
844 }
845 return $subscriber['status'];
846 }
847
848 function mailchimpSF_merge_submit($mv) {
849 // Loop through our Merge Vars, and if they're empty, but required, then print an error, and mark as failed
850 $merge = new stdClass();
851 foreach($mv as $var) {
852 // We also want to create an array where the keys are the tags for easier validation later
853 $tag = $var['tag'];
854 $mv_tag_keys[$tag] = $var;
855
856 $opt = 'mc_mv_' . $tag;
857
858 $opt_val = isset($_POST[$opt]) ? stripslashes_deep($_POST[$opt]) : '';
859
860 // Handle phone number logic
861 if ($var['type'] === 'phone' && $var['options']['phone_format'] === 'US') {
862 $opt_val = mailchimpSF_merge_validate_phone($opt_val, $var);
863 if(is_wp_error($opt_val)) {
864 return $opt_val;
865 }
866 }
867 // Handle address logic
868 else if (is_array($opt_val) && $var['type'] == 'address') {
869 $validate = mailchimpSF_merge_validate_address($opt_val, $var);
870 if(is_wp_error($validate)) {
871 return $validate;
872 }
873
874 if($validate) {
875 $merge->$tag = $validate;
876 }
877 continue;
878
879 }
880 else if (is_array($opt_val)) {
881 $keys = array_keys($opt_val);
882 $val = new stdClass();
883 foreach($keys as $key) {
884 $val->$key = $opt_val[$key];
885 }
886 $opt_val = $val;
887 }
888
889 if ($var['required'] == 'Y' && trim($opt_val) == '') {
890 $message = sprintf(__("You must fill in %s.", 'mailchimp_i18n'), esc_html($var['name']));
891 $error = new WP_Error('missing_required_field', $message);
892 return $error;
893 }
894 else {
895 if ($tag != 'EMAIL') {
896 $merge->$tag = $opt_val;
897 }
898 }
899 }
900 return $merge;
901 }
902
903 function mailchimpSF_merge_validate_phone($opt_val, $var) {
904 // This filters out all 'falsey' elements
905 $opt_val = array_filter($opt_val);
906 // If they weren't all empty
907 if (!$opt_val) {
908 return;
909 }
910
911 $opt_val = implode('-', $opt_val);
912 if (strlen($opt_val) < 12) {
913 $opt_val = '';
914 }
915
916
917 if (!preg_match('/[0-9]{0,3}-[0-9]{0,3}-[0-9]{0,4}/A', $opt_val)) {
918 $message = sprintf(__("%s must consist of only numbers", 'mailchimp_i18n'), esc_html($var['name']));
919 $error = new WP_Error('mc_phone_validation', $message);
920 return $error;
921 }
922
923 return $opt_val;
924 }
925
926 function mailchimpSF_merge_validate_address($opt_val, $var) {
927 if ($var['required'] == 'Y') {
928 if (empty($opt_val['addr1']) || empty($opt_val['city'])) {
929 $message = sprintf(__("You must fill in %s.", 'mailchimp_i18n'), esc_html($var['name']));
930 $error = new WP_Error('invalid_address_merge', $message);
931 return $error;
932 }
933 } else {
934 if (empty($opt_val['addr1']) || empty($opt_val['city'])) {
935 return false;
936 }
937 }
938
939 $merge = new stdClass();
940 $merge->addr1 = $opt_val['addr1'];
941 $merge->addr2 = $opt_val['addr2'];
942 $merge->city = $opt_val['city'];
943 $merge->state = $opt_val['state'];
944 $merge->zip = $opt_val['zip'];
945 $merge->country = $opt_val['country'];
946 return $merge;
947
948 }
949
950 function mailchimpSF_merge_remove_empty($merge)
951 {
952 foreach ($merge as $k => $v) {
953 if (is_object($v) && empty($v)) {
954 unset($merge->$k);
955 } elseif ((is_string($v) && trim($v) === '') || is_null($v)) {
956 unset($merge->$k);
957 }
958 }
959
960 // If we have an empty $merge, then assign empty string.
961 if (count($merge) == 0 || $merge == '') {
962 $merge = '';
963 }
964
965 return $merge;
966 }
967
968 function mailchimpSF_groups_submit($igs) {
969 $groups = mailchimpSF_set_all_groups_to_false();
970
971 if(empty($igs)) {
972 return new StdClass();
973 }
974
975 //get groups and ids
976 //set all to false
977
978 foreach ($igs as $ig) {
979 $ig_id = $ig['id'];
980 if (get_option('mc_show_interest_groups_'.$ig_id) == 'on' && $ig['type'] !== 'hidden') {
981 switch ($ig['type']) {
982 case 'dropdown':
983 case 'radio':
984 // there can only be one value submitted for radio/dropdowns, so use that at the group id.
985 if (isset($_POST['group'][$ig_id]) && !empty($_POST['group'][$ig_id])) {
986 $value = $_POST['group'][$ig_id];
987 $groups->$value = true;
988 }
989 break;
990 case 'checkboxes':
991 if (isset($_POST['group'][$ig_id])) {
992 foreach ($_POST['group'][$ig_id] as $id => $value) {
993 $groups->$id = true;
994 }
995 }
996 break;
997 default:
998 // Nothing
999 break;
1000 }
1001 }
1002 }
1003 return $groups;
1004 }
1005
1006 function mailchimpSF_set_all_groups_to_false() {
1007 $toreturn = new StdClass();
1008
1009 foreach (get_option('mc_interest_groups') as $grouping) {
1010 if($grouping['type'] !== 'hidden') {
1011 foreach ($grouping['groups'] as $group) {
1012 $id = $group['id'];
1013 $toreturn->$id = false;
1014 }
1015 }
1016 }
1017
1018 return $toreturn;
1019 }
1020
1021 function mailchimpSF_verify_key($api) {
1022 $user = $api->get('');
1023 if (is_wp_error($user)) {
1024 return $user;
1025 }
1026
1027 //Might as well set this data if we have it already.
1028 $valid_roles = array('owner', 'admin', 'manager');
1029 if(in_array($user['role'], $valid_roles)) {
1030 update_option('mc_api_key', $api->key);
1031 update_option('mc_user', $user);
1032 update_option('mc_datacenter', $api->datacenter);
1033
1034 } else {
1035 $msg = __('API Key must belong to "Owner", "Admin", or "Manager."', 'mailchimp_i18n');
1036 return new WP_Error('mc-invalid-role', $msg);
1037 }
1038 return;
1039 }
1040
1041 function mailchimpSF_update_profile_url($email) {
1042 $dc = get_option('mc_datacenter');
1043 $eid = base64_encode($email);
1044 $user = get_option('mc_user');
1045 $list_id = get_option('mc_list_id');
1046 $url = 'http://' . $dc . '.list-manage.com/subscribe/send-email?u=' . $user['account_id'] . '&id=' . $list_id . '&e=' . $eid;
1047 return $url;
1048 }
1049
1050 function mailchimpSF_signup_form_url() {
1051 $dc = get_option('mc_datacenter');
1052 $user = get_option('mc_user');
1053 $list_id = get_option('mc_list_id');
1054 $url = 'http://' . $dc . '.list-manage.com/subscribe?u=' . $user['account_id'] . '&id=' . $list_id;
1055 return $url;
1056 }
1057
1058 function mailchimpSF_delete_options($options = array()) {
1059 foreach($options as $option) {
1060 delete_option($option);
1061 }
1062 }
1063
1064
1065 /**********************
1066 * Utility Functions *
1067 **********************/
1068 /**
1069 * Utility function to allow placement of plugin in plugins, mu-plugins, child or parent theme's plugins folders
1070 *
1071 * This function must be ran _very early_ in the load process, as it sets up important constants for the rest of the plugin
1072 */
1073 function mailchimpSF_where_am_i() {
1074 $locations = array(
1075 'plugins' => array(
1076 'dir' => plugin_dir_path(__FILE__),
1077 'url' => plugins_url()
1078 ),
1079 'mu_plugins' => array(
1080 'dir' => plugin_dir_path(__FILE__),
1081 'url' => plugins_url(),
1082 ),
1083 'template' => array(
1084 'dir' => trailingslashit(get_template_directory()).'plugins/',
1085 'url' => trailingslashit(get_template_directory_uri()).'plugins/',
1086 ),
1087 'stylesheet' => array(
1088 'dir' => trailingslashit(get_stylesheet_directory()).'plugins/',
1089 'url' => trailingslashit(get_stylesheet_directory_uri()).'plugins/',
1090 ),
1091 );
1092
1093 // Set defaults
1094 $mscf_dirbase = trailingslashit(basename(dirname(__FILE__))); // Typically wp-mailchimp/ or mailchimp/
1095 $mscf_dir = trailingslashit(plugin_dir_path(__FILE__));
1096 $mscf_url = trailingslashit(plugins_url(null, __FILE__));
1097
1098 // Try our hands at finding the real location
1099 foreach ($locations as $key => $loc) {
1100 $dir = trailingslashit($loc['dir']).$mscf_dirbase;
1101 $url = trailingslashit($loc['url']).$mscf_dirbase;
1102 if (is_file($dir.basename(__FILE__))) {
1103 $mscf_dir = $dir;
1104 $mscf_url = $url;
1105 break;
1106 }
1107 }
1108
1109 // Define our complete filesystem path
1110 define('MCSF_DIR', $mscf_dir);
1111
1112 /* Lang location needs to be relative *from* ABSPATH,
1113 so strip it out of our language dir location */
1114 define('MCSF_LANG_DIR', trailingslashit(MCSF_DIR).'po/');
1115
1116 // Define our complete URL to the plugin folder
1117 define('MCSF_URL', $mscf_url);
1118 }
1119
1120
1121 /**
1122 * MODIFIED VERSION of wp_verify_nonce from WP Core. Core was not overridden to prevent problems when replacing
1123 * something universally.
1124 *
1125 * Verify that correct nonce was used with time limit.
1126 *
1127 * The user is given an amount of time to use the token, so therefore, since the
1128 * UID and $action remain the same, the independent variable is the time.
1129 *
1130 * @param string $nonce Nonce that was used in the form to verify
1131 * @param string|int $action Should give context to what is taking place and be the same when nonce was created.
1132 * @return bool Whether the nonce check passed or failed.
1133 */
1134 function mailchimpSF_verify_nonce($nonce, $action = -1) {
1135 $user = wp_get_current_user();
1136 $uid = (int) $user->ID;
1137 if ( ! $uid ) {
1138 $uid = apply_filters( 'nonce_user_logged_out', $uid, $action );
1139 }
1140
1141 if ( empty( $nonce ) ) {
1142 return false;
1143 }
1144
1145 $token = 'MAILCHIMP';
1146 $i = wp_nonce_tick();
1147
1148 // Nonce generated 0-12 hours ago
1149 $expected = substr( wp_hash( $i . '|' . $action . '|' . $uid . '|' . $token, 'nonce'), -12, 10 );
1150 if ( hash_equals( $expected, $nonce ) ) {
1151 return 1;
1152 }
1153
1154 // Nonce generated 12-24 hours ago
1155 $expected = substr( wp_hash( ( $i - 1 ) . '|' . $action . '|' . $uid . '|' . $token, 'nonce' ), -12, 10 );
1156 if ( hash_equals( $expected, $nonce ) ) {
1157 return 2;
1158 }
1159
1160 // Invalid nonce
1161 return false;
1162 }
1163
1164
1165 /**
1166 * MODIFIED VERSION of wp_create_nonce from WP Core. Core was not overridden to prevent problems when replacing
1167 * something universally.
1168 *
1169 * Creates a cryptographic token tied to a specific action, user, and window of time.
1170 *
1171 * @param string $action Scalar value to add context to the nonce.
1172 * @return string The token.
1173 */
1174 function mailchimpSF_create_nonce($action = -1) {
1175 $user = wp_get_current_user();
1176 $uid = (int) $user->ID;
1177 if ( ! $uid ) {
1178 /** This filter is documented in wp-includes/pluggable.php */
1179 $uid = apply_filters( 'nonce_user_logged_out', $uid, $action );
1180 }
1181
1182 $token = 'MAILCHIMP';
1183 $i = wp_nonce_tick();
1184
1185 return substr( wp_hash( $i . '|' . $action . '|' . $uid . '|' . $token, 'nonce' ), -12, 10 );
1186 }