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

1,186 lines 39.0 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.3
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.3');
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 if (get_option('mc_list_id') && get_option('mc_merge_field_migrate') != true && mailchimpSF_get_api() !== false) {
66 mailchimpSF_update_merge_fields(get_option('mc_list_id'));
67 }
68
69 // Bring in our appropriate JS and CSS resources
70 mailchimpSF_load_resources();
71 }
72
73 add_action( 'init', 'mailchimpSF_plugin_init' );
74
75
76 /**
77 * Add the settings link to the MailChimp plugin row
78 *
79 * @param array $links - Links for the plugin
80 * @return array - Links
81 */
82 function mailchimpSD_plugin_action_links($links) {
83 $settings_page = add_query_arg(array('page' => 'mailchimpSF_options'), admin_url('options-general.php'));
84 $settings_link = '<a href="'.esc_url($settings_page).'">'.__('Settings', 'mailchimp_i18n' ).'</a>';
85 array_unshift($links, $settings_link);
86 return $links;
87 }
88 add_filter('plugin_action_links_'.plugin_basename(__FILE__), 'mailchimpSD_plugin_action_links', 10, 1);
89
90 /**
91 * Loads the appropriate JS and CSS resources depending on
92 * settings and context (admin or not)
93 *
94 * @return void
95 */
96 function mailchimpSF_load_resources() {
97 // JS
98 if (get_option('mc_use_javascript') == 'on') {
99 if (!is_admin()) {
100 wp_enqueue_script('jquery_scrollto', MCSF_URL.'js/scrollTo.js', array('jquery'), MCSF_VER);
101 wp_enqueue_script('mailchimpSF_main_js', MCSF_URL.'js/mailchimp.js', array('jquery', 'jquery-form'), MCSF_VER);
102 // some javascript to get ajax version submitting to the proper location
103 global $wp_scripts;
104 $wp_scripts->localize('mailchimpSF_main_js', 'mailchimpSF', array(
105 'ajax_url' => trailingslashit(home_url()),
106 ));
107 }
108 }
109
110 if (get_option('mc_use_datepicker') == 'on' && !is_admin()) {
111 // Datepicker theme
112 wp_enqueue_style('flick', MCSF_URL.'/css/flick/flick.css'
113 );
114 // Datepicker JS
115 wp_enqueue_script('datepicker', MCSF_URL.'/js/datepicker.js', array('jquery','jquery-ui-core'));
116 }
117
118 if(get_option('mc_nuke_all_styles') != true) {
119 wp_enqueue_style('mailchimpSF_main_css', home_url('?mcsf_action=main_css&ver='.MCSF_VER, 'relative'));
120 wp_enqueue_style('mailchimpSF_ie_css', MCSF_URL.'css/ie.css');
121 global $wp_styles;
122 $wp_styles->add_data( 'mailchimpSF_ie_css', 'conditional', 'IE' );
123 }
124 }
125
126
127 /**
128 * Loads resources for the MailChimp admin page
129 *
130 * @return void
131 */
132 function mc_admin_page_load_resources() {
133 wp_enqueue_style('mailchimpSF_admin_css', MCSF_URL.'css/admin.css');
134 }
135 add_action('load-settings_page_mailchimpSF_options', 'mc_admin_page_load_resources');
136
137
138 /**
139 * Loads jQuery Datepicker for the date-pick class
140 **/
141 function mc_datepicker_load() {
142 require_once(MCSF_DIR . '/views/datepicker.php');
143 }
144 if (get_option('mc_use_datepicker') == 'on' && !is_admin()) {
145 add_action('wp_head', 'mc_datepicker_load');
146 }
147
148 /**
149 * Handles requests that as light-weight a load as possible.
150 * typically, JS or CSS
151 **/
152 function mailchimpSF_early_request_handler() {
153 if (isset($_GET['mcsf_action'])) {
154 switch ($_GET['mcsf_action']) {
155 case 'main_css':
156 header("Content-type: text/css");
157 mailchimpSF_main_css();
158 exit;
159 }
160 }
161 }
162 add_action('init', 'mailchimpSF_early_request_handler', 0);
163
164 /**
165 * Outputs the front-end CSS. This checks several options, so it
166 * was best to put it in a Request-handled script, as opposed to
167 * a static file.
168 */
169 function mailchimpSF_main_css() {
170 require_once(MCSF_DIR . '/views/css/frontend.php');
171 }
172
173
174 /**
175 * Add our settings page to the admin menu
176 *
177 * @return void
178 */
179 function mailchimpSF_add_pages(){
180 // Add settings page for users who can edit plugins
181 add_options_page( __( 'MailChimp Setup', 'mailchimp_i18n' ), __( 'MailChimp Setup', 'mailchimp_i18n' ), MCSF_CAP_THRESHOLD, 'mailchimpSF_options', 'mailchimpSF_setup_page');
182 }
183 add_action('admin_menu', 'mailchimpSF_add_pages');
184
185 function mailchimpSF_request_handler() {
186 if (isset($_POST['mcsf_action'])) {
187 switch ($_POST['mcsf_action']) {
188 case 'login':
189 $key = trim($_POST['mailchimpSF_api_key']);
190
191 try {
192 $api = new MailChimp_API($key);
193 } catch (Exception $e) {
194 $msg = "<strong class='mc_error_msg'>" . $e->getMessage() . "</strong>";
195 mailchimpSF_global_msg($msg);
196 break;
197 }
198
199 $key = mailchimpSF_verify_key($api);
200 if(is_wp_error($key)) {
201 $msg = "<strong class='mc_error_msg'>" . $key->get_error_message() . "</strong>";
202 mailchimpSF_global_msg($msg);
203 }
204
205 break;
206 case 'logout':
207 // Check capability & Verify nonce
208 if (!current_user_can(MCSF_CAP_THRESHOLD) || !wp_verify_nonce($_POST['_mcsf_nonce_action'], 'mc_logout')) {
209 wp_die('Cheatin&rsquo; huh?');
210 }
211
212 // erase auth information
213 $options = array('mc_api_key', 'mc_sopresto_user', 'mc_sopresto_public_key', 'mc_sopresto_secret_key');
214 mailchimpSF_delete_options($options);
215 break;
216 case 'change_form_settings':
217 if (!current_user_can(MCSF_CAP_THRESHOLD) || !wp_verify_nonce($_POST['_mcsf_nonce_action'], 'update_general_form_settings')) {
218 wp_die('Cheatin&rsquo; huh?');
219 }
220
221 // Update the form settings
222 mailchimpSF_save_general_form_settings();
223 break;
224 case 'mc_submit_signup_form':
225 // Validate nonce
226 if (!wp_verify_nonce($_POST['_mc_submit_signup_form_nonce'], 'mc_submit_signup_form')) {
227 wp_die('Cheatin&rsquo; huh?');
228 }
229
230 // Attempt the signup
231 mailchimpSF_signup_submit();
232
233 // Do a different action for html vs. js
234 switch ($_POST['mc_submit_type']) {
235 case 'html':
236 /* Allow to fall through. The widget will pick up the
237 * global message left over from the signup_submit function */
238 case 'js':
239 if (!headers_sent()){ //just in case...
240 header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT', true, 200);
241 }
242 echo mailchimpSF_global_msg(); // Don't esc_html this, b/c we've already escaped it
243 exit;
244 }
245 }
246 }
247 }
248 add_action('init', 'mailchimpSF_request_handler');
249
250 function mailchimpSF_migrate_sopresto() {
251 $sopresto = get_option('mc_sopresto_secret_key');
252 if(!$sopresto) {
253 return;
254 }
255
256 // Talk to Sopresto, make exchange, delete old sopresto things.
257 $body = array(
258 'public_key' => get_option('mc_sopresto_public_key'),
259 'hash' => sha1(get_option('mc_sopresto_public_key').get_option('mc_sopresto_secret_key'))
260 );
261
262 $url = 'https://sopresto.socialize-this.com/mailchimp/exchange';
263 $args = array(
264 'method' => 'POST',
265 'timeout' => 500,
266 'redirection' => 5,
267 'httpversion' => '1.0',
268 'user-agent' => 'MailChimp WordPress Plugin/' . get_bloginfo( 'url' ),
269 'body' => $body
270 );
271
272 //post to sopresto
273 $key = wp_remote_post($url, $args);
274 if(!is_wp_error($key) && $key['response']['code'] == 200) {
275 $key = json_decode($key['body']);
276 try {
277 $api = new MailChimp_API($key->response);
278 } catch (Exception $e) {
279 $msg = "<strong class='mc_error_msg'>" . $e->getMessage() . "</strong>";
280 mailchimpSF_global_msg($msg);
281 return;
282 }
283
284 $verify = mailchimpSF_verify_key($api);
285
286 //something went wrong with the key that we had
287 if(is_wp_error($verify)) {
288 return;
289 }
290
291 delete_option('mc_sopresto_public_key');
292 delete_option('mc_sopresto_secret_key');
293 delete_option('mc_sopresto_user');
294
295 return;
296 }
297
298 // Nothing to do here.
299 return;
300 }
301
302 function mailchimpSF_update_merge_fields($list_id)
303 {
304 mailchimpSF_get_merge_vars(get_option('mc_list_id'), true);
305 mailchimpSF_get_interest_categories(get_option('mc_list_id'), true);
306 update_option('mc_merge_field_migrate', true);
307 }
308
309 function mailchimpSF_auth_nonce_key($salt = null) {
310 if (is_null($salt)) {
311 $salt = mailchimpSF_auth_nonce_salt();
312 }
313 return 'social_authentication' . md5( AUTH_KEY . $salt );
314 }
315
316 function mailchimpSF_auth_nonce_salt() {
317 return md5(microtime().$_SERVER['SERVER_ADDR']);
318 }
319
320 /**
321 * Creates new MailChimp API v3 object
322 *
323 * @return MailChimp_API | false
324 */
325
326 function mailchimpSF_get_api($force = false) {
327 $key = get_option('mc_api_key');
328 if($key) {
329 return new MailChimp_API($key);
330 }
331
332 return false;
333 }
334
335
336
337 /**
338 * Checks to see if we're storing a password, if so, we need
339 * to upgrade to the API key
340 *
341 * @return bool
342 **/
343 function mailchimpSF_needs_upgrade() {
344 $igs = get_option('mc_interest_groups');
345
346 if ($igs !== false // we have an option
347 && (
348 empty($igs) || // it can be an empty array (no interest groups)
349 (is_array($igs) && isset($igs[0]['id'])) // OR it should be a populated array that's well-formed
350 )) {
351 return false; // no need to upgrade
352 }
353 else {
354 return true; // yeah, let's do it
355 }
356 }
357
358 /**
359 * Deletes all mailchimp options
360 **/
361 function mailchimpSF_delete_setup() {
362 $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');
363
364 $igs = get_option('mc_interest_groups');
365 if (is_array($igs)) {
366 foreach ($igs as $ig) {
367 $opt = 'mc_show_interest_groups_'.$ig['id'];
368 $options[] = $opt;
369 }
370 }
371
372 $mv = get_option('mc_merge_vars');
373 if (is_array($mv)){
374 foreach($mv as $var){
375 $opt = 'mc_mv_'.$var['tag'];
376 $options[] = $opt;
377 }
378 }
379
380 mailchimpSF_delete_options($options);
381 }
382
383 /**
384 * Gets or sets a global message based on parameter passed to it
385 *
386 * @return string/bool depending on get/set
387 **/
388 function mailchimpSF_global_msg($msg = null) {
389 global $mcsf_msgs;
390
391 // Make sure we're formed properly
392 if (!is_array($mcsf_msgs)) {
393 $mcsf_msgs = array();
394 }
395
396 // See if we're getting
397 if (is_null($msg)) {
398 return implode('', $mcsf_msgs);
399 }
400
401 // Must be setting
402 $mcsf_msgs[] = $msg;
403 return true;
404 }
405
406 /**
407 * Sets the default options for the option form
408 **/
409 function mailchimpSF_set_form_defaults($list_name = '') {
410 update_option('mc_header_content',__( 'Sign up for', 'mailchimp_i18n' ).' '.$list_name);
411 update_option('mc_submit_text',__( 'Subscribe', 'mailchimp_i18n' ));
412
413 update_option('mc_use_datepicker', 'on');
414 update_option('mc_custom_style','off');
415 update_option('mc_use_javascript','on');
416 update_option('mc_double_optin', true);
417 update_option('mc_use_unsub_link','off');
418 update_option('mc_header_border_width','1');
419 update_option('mc_header_border_color','E3E3E3');
420 update_option('mc_header_background','FFFFFF');
421 update_option('mc_header_text_color','CC6600');
422
423 update_option('mc_form_border_width','1');
424 update_option('mc_form_border_color','E0E0E0');
425 update_option('mc_form_background','FFFFFF');
426 update_option('mc_form_text_color','3F3F3f');
427 }
428
429 /**
430 * Saves the General Form settings on the options page
431 *
432 * @return void
433 **/
434 function mailchimpSF_save_general_form_settings() {
435
436 // IF NOT DEV MODE
437 if (isset($_POST['mc_rewards'])){
438 update_option('mc_rewards', 'on');
439 $msg = '<p class="success_msg">'.__('Monkey Rewards turned On!', 'mailchimp_i18n').'</p>';
440 mailchimpSF_global_msg($msg);
441 } else if (get_option('mc_rewards')!='off') {
442 update_option('mc_rewards', 'off');
443 $msg = '<p class="success_msg">'.__('Monkey Rewards turned Off!', 'mailchimp_i18n').'</p>';
444 mailchimpSF_global_msg($msg);
445 }
446 if (isset($_POST['mc_use_javascript'])){
447 update_option('mc_use_javascript', 'on');
448 $msg = '<p class="success_msg">'.__('Fancy Javascript submission turned On!', 'mailchimp_i18n').'</p>';
449 mailchimpSF_global_msg($msg);
450 } else if (get_option('mc_use_javascript')!='off') {
451 update_option('mc_use_javascript', 'off');
452 $msg = '<p class="success_msg">'.__('Fancy Javascript submission turned Off!', 'mailchimp_i18n').'</p>';
453 mailchimpSF_global_msg($msg);
454 }
455
456 if (isset($_POST['mc_use_datepicker'])){
457 update_option('mc_use_datepicker', 'on');
458 $msg = '<p class="success_msg">'.__('Datepicker turned On!', 'mailchimp_i18n').'</p>';
459 mailchimpSF_global_msg($msg);
460 } else if (get_option('mc_use_datepicker')!='off') {
461 update_option('mc_use_datepicker', 'off');
462 $msg = '<p class="success_msg">'.__('Datepicker turned Off!', 'mailchimp_i18n').'</p>';
463 mailchimpSF_global_msg($msg);
464 }
465
466 /*Enable double optin toggle*/
467
468 if(isset($_POST['mc_double_optin'])) {
469 update_option('mc_double_optin', true);
470 $msg = '<p class="success_msg">'.__('Double opt-in turned On!', 'mailchimp_i18n').'</p>';
471 mailchimpSF_global_msg($msg);
472 } else if (get_option('mc_double_optin') != false) {
473 update_option('mc_double_optin', false);
474 $msg = '<p class="success_msg">'.__('Double opt-in turned Off!', 'mailchimp_i18n').'</p>';
475 mailchimpSF_global_msg($msg);
476 }
477
478 /* NUKE the CSS! */
479 if(isset($_POST['mc_nuke_all_styles'])) {
480 update_option('mc_nuke_all_styles', true);
481 $msg = '<p class="success_msg">'.__('MailChimp CSS turned Off!', 'mailchimp_i18n').'</p>';
482 mailchimpSF_global_msg($msg);
483 }elseif (get_option('mc_nuke_all_styles') !== false) {
484 update_option('mc_nuke_all_styles', false);
485 $msg = '<p class="success_msg">'.__('MailChimp CSS turned On!', 'mailchimp_i18n').'</p>';
486 mailchimpSF_global_msg($msg);
487 }
488
489 /* Update existing */
490 if (isset($_POST['mc_update_existing'])) {
491 update_option('mc_update_existing', true);
492 $msg = '<p class="success_msg">' . __('Update existing subscribers turned On!') . '</p>';
493 mailchimpSF_global_msg($msg);
494 } elseif (get_option('mc_update_existing') ==! false) {
495 update_option('mc_update_existing', false);
496 $msg = '<p class="success_msg">' . __('Update existing subscribers turned Off!') . '</p>';
497 mailchimpSF_global_msg($msg);
498 }
499
500 if (isset($_POST['mc_use_unsub_link'])){
501 update_option('mc_use_unsub_link', 'on');
502 $msg = '<p class="success_msg">'.__('Unsubscribe link turned On!', 'mailchimp_i18n').'</p>';
503 mailchimpSF_global_msg($msg);
504 }
505
506 elseif (get_option('mc_use_unsub_link')!='off') {
507 update_option('mc_use_unsub_link', 'off');
508 $msg = '<p class="success_msg">'.__('Unsubscribe link turned Off!', 'mailchimp_i18n').'</p>';
509 mailchimpSF_global_msg($msg);
510 }
511
512 $content = stripslashes($_POST['mc_header_content']);
513 $content = str_replace("\r\n","<br/>", $content);
514 update_option('mc_header_content', $content );
515
516 $content = stripslashes($_POST['mc_subheader_content']);
517 $content = str_replace("\r\n","<br/>", $content);
518 update_option('mc_subheader_content', $content );
519
520
521 $submit_text = stripslashes($_POST['mc_submit_text']);
522 $submit_text = str_replace("\r\n","", $submit_text);
523 update_option('mc_submit_text', $submit_text);
524
525 // Set Custom Style option
526 update_option('mc_custom_style', isset($_POST['mc_custom_style']) ? 'on' : 'off');
527
528 //we told them not to put these things we are replacing in, but let's just make sure they are listening...
529 if(isset($_POST['mc_form_border_width'])) {
530 update_option('mc_form_border_width',str_replace('px', '', $_POST['mc_form_border_width']) );
531 }
532 if(isset($_POST['mc_form_border_color'])) {
533 update_option('mc_form_border_color', str_replace('#', '', $_POST['mc_form_border_color']));
534 }
535 if(isset($_POST['mc_form_background'])){
536 update_option('mc_form_background',str_replace('#', '', $_POST['mc_form_background']));
537 }
538 if(isset($_POST['mc_form_text_color'])) {
539 update_option('mc_form_text_color', str_replace('#', '', $_POST['mc_form_text_color']));
540 }
541
542
543 // IF NOT DEV MODE
544 $igs = get_option('mc_interest_groups');
545 if (is_array($igs)) {
546 foreach($igs as $var){
547 $opt = 'mc_show_interest_groups_'.$var['id'];
548 if (isset($_POST[$opt])){
549 update_option($opt,'on');
550 } else {
551 update_option($opt,'off');
552 }
553 }
554 }
555
556 $mv = get_option('mc_merge_vars');
557 if (is_array($mv)) {
558 foreach($mv as $var){
559 $opt = 'mc_mv_'.$var['tag'];
560 if (isset($_POST[$opt]) || $var['required']=='Y'){
561 update_option($opt,'on');
562 } else {
563 update_option($opt,'off');
564 }
565 }
566 }
567
568 $msg = '<p class="success_msg">'.esc_html(__('Successfully Updated your List Subscribe Form Settings!', 'mailchimp_i18n')).'</p>';
569 mailchimpSF_global_msg($msg);
570 }
571
572 /**
573 * Sees if the user changed the list, and updates options accordingly
574 **/
575 function mailchimpSF_change_list_if_necessary() {
576 // Simple permission check before going through all this
577 if (!current_user_can(MCSF_CAP_THRESHOLD)) { return; }
578
579 $api = mailchimpSF_get_api();
580 if (!$api) { return; }
581
582 //we *could* support paging, but few users have that many lists (and shouldn't)
583 $lists = $api->get('lists',100, array('fields' => 'lists.id,lists.name,lists.email_type_option'));
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 }