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

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