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

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