PluginProbe
Mailchimp List Subscribe Form / trunk
Mailchimp List Subscribe Form vtrunk
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
← All changes | mailchimp.php +830 -945 1.2.4trunk View file →
@@ -1,413 +1,413 @@
1 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.2.4
7 -Author: MailChimp and Crowd Favorite
8 -Author URI: http://mailchimp.com/api/
9 -*/
10 -/* Copyright 2008 MailChimp.com (email : api@mailchimp.com)
2 +/**
3 + * Plugin Name: Mailchimp
4 + * Plugin URI: https://mailchimp.com/help/connect-or-disconnect-list-subscribe-for-wordpress/
5 + * Description: Add a Mailchimp signup form block, widget or shortcode to your WordPress site.
6 + * Text Domain: mailchimp
7 + * Version: 2.1.0
8 + * Requires at least: 6.6
9 + * Requires PHP: 7.4
10 + * PHP tested up to: 8.3
11 + * Author: Mailchimp
12 + * Author URI: https://mailchimp.com/
13 + * License: GPL-2.0-or-later
14 + * License URI: https://spdx.org/licenses/GPL-2.0-or-later.html
15 + *
16 + * @package Mailchimp
17 + **/
11 18
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.
19 +/**
20 + * Copyright 2008-2012 Mailchimp.com (email : api@mailchimp.com)
21 + *
22 + * This program is free software; you can redistribute it and/or modify
23 + * it under the terms of the GNU General Public License as published by
24 + * the Free Software Foundation; either version 2 of the License, or
25 + * (at your option) any later version.
26 + *
27 + * This program is distributed in the hope that it will be useful,
28 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
29 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30 + * GNU General Public License for more details.
31 + *
32 + * You should have received a copy of the GNU General Public License
33 + * along with this program; if not, write to the Free Software
34 + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
35 + */
16 36
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.
37 +// Check if the autoload file exists
38 +if ( is_readable( __DIR__ . '/vendor/autoload.php' ) ) {
39 + require_once __DIR__ . '/vendor/autoload.php';
40 +} else {
41 + add_action(
42 + 'admin_notices',
43 + function () {
44 + ?>
45 + <div class="notice notice-error">
46 + <p>
47 + <?php
48 + echo wp_kses_post(
49 + sprintf(
50 + /* translators: 1: Command to run, e.g., <code>composer install</code>, 2: Support URL, e.g., https://wordpress.org/support/plugin/mailchimp/. */
51 + __( 'The composer autoload file is not found or not readable. Please contact <a href="%2$s" target="_blank">support</a> if you\'re a user. Please run %1$s if you\'re a developer in a development environment.', 'mailchimp' ),
52 + '<code>composer install</code>',
53 + 'https://wordpress.org/support/plugin/mailchimp/'
54 + )
55 + );
56 + ?>
57 + </p>
58 + </div>
59 + <?php
60 + }
61 + );
21 62
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 -*/
63 + // Exit early.
64 + return;
65 +}
26 66
67 +use function Mailchimp\WordPress\Includes\Admin\{admin_notice_error, admin_notice_success};
68 +
27 69 // Version constant for easy CSS refreshes
28 -define('MCSF_VER', '1.2.4');
70 +define( 'MCSF_VER', '2.1.0' );
29 71
30 72 // What's our permission (capability) threshold
31 -define('MCSF_CAP_THRESHOLD', 'edit_plugins');
73 +define( 'MCSF_CAP_THRESHOLD', 'manage_options' );
32 74
33 75 // Define our location constants, both MCSF_DIR and MCSF_URL
34 -mailchimpSF_where_am_i();
76 +mailchimp_sf_where_am_i();
35 77
36 -// Get our MailChimp API class in scope
37 -if (!class_exists('mailchimpSF_MCAPI')) {
38 - require_once('miniMCAPI.class.php');
78 +// Get our Mailchimp API class in scope
79 +if ( ! class_exists( 'MailChimp_API' ) ) {
80 + $path = plugin_dir_path( __FILE__ );
81 + require_once $path . 'lib/mailchimp/mailchimp.php';
39 82 }
40 83
84 +// Encryption utility class.
85 +require_once plugin_dir_path( __FILE__ ) . 'includes/class-mailchimp-data-encryption.php';
86 +
41 87 // includes the widget code so it can be easily called either normally or via ajax
42 -include_once('mailchimp_widget.php');
88 +require_once 'mailchimp_widget.php';
43 89
44 90 // includes the backwards compatibility functions
45 -include_once('mailchimp_compat.php');
91 +require_once 'mailchimp_compat.php';
46 92
93 +// Upgrade routines.
94 +require_once 'mailchimp_upgrade.php';
47 95
96 +// Init Admin functions.
97 +require_once plugin_dir_path( __FILE__ ) . 'includes/class-mailchimp-user-sync-backgroud-process.php';
98 +require_once plugin_dir_path( __FILE__ ) . 'includes/admin/class-mailchimp-user-sync.php';
99 +require_once plugin_dir_path( __FILE__ ) . 'includes/admin/class-mailchimp-admin-notices.php';
100 +require_once plugin_dir_path( __FILE__ ) . 'includes/class-mailchimp-admin.php';
101 +$admin = new Mailchimp_Admin();
102 +$admin->init();
48 103
104 +// Init the blocks.
105 +require_once plugin_dir_path( __FILE__ ) . 'includes/blocks/class-mailchimp-list-subscribe-form-blocks.php';
106 +$block = new Mailchimp_List_Subscribe_Form_Blocks();
107 +$block->init();
49 108
109 +// Form submission handler class.
110 +require_once plugin_dir_path( __FILE__ ) . 'includes/class-mailchimp-form-submission.php';
111 +$form_submission = new Mailchimp_Form_Submission();
112 +$form_submission->init();
113 +
114 +// Shared bucketing helpers used by both analytics chart data providers.
115 +require_once plugin_dir_path( __FILE__ ) . 'includes/trait-mailchimp-analytics-bucketing.php';
116 +
117 +// Init Analytics page.
118 +require_once plugin_dir_path( __FILE__ ) . 'includes/class-mailchimp-analytics.php';
119 +$analytics = new Mailchimp_Analytics();
120 +$analytics->init();
121 +
122 +// Analytics data class.
123 +require_once plugin_dir_path( __FILE__ ) . 'includes/class-mailchimp-analytics-data.php';
124 +$analytics_data = new Mailchimp_Analytics_Data();
125 +$analytics_data->init();
126 +
127 +// Subscriber activity (Mailchimp Activity API) data class.
128 +require_once plugin_dir_path( __FILE__ ) . 'includes/class-mailchimp-subscriber-activity.php';
129 +$subscriber_activity = new Mailchimp_Subscriber_Activity();
130 +$subscriber_activity->init();
131 +
132 +// Form performance (local analytics DB) data class.
133 +require_once plugin_dir_path( __FILE__ ) . 'includes/class-mailchimp-form-performance.php';
134 +$form_performance = new Mailchimp_Form_Performance();
135 +$form_performance->init();
136 +
137 +// Deprecated functions.
138 +require_once plugin_dir_path( __FILE__ ) . 'includes/mailchimp-deprecated-functions.php';
139 +
50 140 /**
51 141 * Do the following plugin setup steps here
52 142 *
53 - * Internationalization
54 143 * Resource (JS & CSS) enqueuing
55 144 *
56 145 * @return void
57 146 */
58 -function mailchimpSF_plugin_init() {
59 - // Internationalize the plugin
60 - load_plugin_textdomain( 'mailchimp_i18n', MCSF_LANG_DIR.'po/');
147 +function mailchimp_sf_plugin_init() {
61 148
62 - // Bring in our appropriate JS and CSS resources
63 - mailchimpSF_load_resources();
149 + if ( get_option( 'mc_list_id' ) && get_option( 'mc_merge_field_migrate' ) !== '1' && mailchimp_sf_get_api() !== false ) {
150 + mailchimp_sf_update_merge_fields();
151 + }
152 +
153 + if ( mailchimp_sf_should_display_form() ) {
154 + // Bring in our appropriate JS and CSS resources
155 + add_action( 'wp_enqueue_scripts', 'mailchimp_sf_load_resources' );
156 + }
64 157 }
65 -add_action( 'init', 'mailchimpSF_plugin_init' );
66 158
159 +add_action( 'init', 'mailchimp_sf_plugin_init' );
160 +
67 161 /**
68 - * Loads the appropriate JS and CSS resources depending on
162 + * Add the settings link to the Mailchimp plugin row
163 + *
164 + * @param array $links - Links for the plugin
165 + * @return array - Links
166 + */
167 +function mailchimp_sf_plugin_action_links( $links ) {
168 + $settings_page = add_query_arg( array( 'page' => 'mailchimp_sf_options' ), admin_url( 'admin.php' ) );
169 + $settings_link = '<a href="' . esc_url( $settings_page ) . '">' . esc_html__( 'Settings', 'mailchimp' ) . '</a>';
170 + array_unshift( $links, $settings_link );
171 + return $links;
172 +}
173 +
174 +add_filter( 'plugin_action_links_' . plugin_basename( __FILE__ ), 'mailchimp_sf_plugin_action_links', 10, 1 );
175 +
176 +/**
177 + * Loads the appropriate JS and CSS resources depending on
69 178 * settings and context (admin or not)
70 179 *
71 180 * @return void
72 181 */
73 -function mailchimpSF_load_resources() {
182 +function mailchimp_sf_load_resources() {
74 183 // JS
75 - if (get_option('mc_use_javascript') == 'on') {
76 - if (!is_admin()) {
77 - wp_enqueue_script('mailchimpSF_main_js', MCSF_URL.'js/mailchimp.js', array('jquery', 'jquery-form'), MCSF_VER);
78 - // some javascript to get ajax version submitting to the proper location
79 - global $wp_scripts;
80 - $wp_scripts->localize('mailchimpSF_main_js', 'mailchimpSF', array(
81 - 'ajax_url' => trailingslashit(home_url()),
82 - ));
83 - }
184 + wp_enqueue_script( 'mailchimp_sf_main_js', MCSF_URL . 'assets/js/mailchimp.js', array( 'jquery', 'jquery-form', 'jquery-ui-datepicker' ), MCSF_VER, true );
185 + // some javascript to get ajax version submitting to the proper location
186 + global $wp_scripts;
187 + $localize_data = array(
188 + 'ajax_url' => trailingslashit( home_url() ),
189 + 'phone_validation_error' => esc_html__( 'Please enter a valid phone number.', 'mailchimp' ),
190 + );
191 +
192 + if ( ! is_admin() ) {
193 + $localize_data['analytics_ajax_url'] = admin_url( 'admin-ajax.php' );
194 + $localize_data['analytics_nonce'] = wp_create_nonce( 'mailchimp_sf_analytics_nonce' );
84 195 }
85 -
196 +
197 + $wp_scripts->localize(
198 + 'mailchimp_sf_main_js',
199 + 'mailchimpSF',
200 + $localize_data
201 + );
202 +
203 + // Datepicker theme
204 + wp_enqueue_style( 'flick', MCSF_URL . 'assets/css/flick/flick.css', array(), MCSF_VER );
205 +
86 206 // CSS
87 - if (is_admin() && $_GET['page'] == 'mailchimpSF_options') {
88 - wp_enqueue_style('mailchimpSF_admin_css', MCSF_URL.'css/admin.css');
89 - }
90 - else {
91 - wp_enqueue_style('mailchimpSF_main_css', home_url('?mcsf_action=main_css&ver='.MCSF_VER));
92 - wp_enqueue_style('mailchimpSF_ie_css', MCSF_URL.'css/ie.css');
93 - global $wp_styles;
94 - $wp_styles->add_data( 'mailchimpSF_ie_css', 'conditional', 'IE' );
95 - }
96 -}
207 + if ( get_option( 'mc_nuke_all_styles' ) !== '1' ) {
208 + wp_enqueue_style( 'mailchimp_sf_main_css', MCSF_URL . 'assets/css/frontend.css', array(), MCSF_VER );
97 209
98 -/**
99 - * Handles requests that as light-weight a load as possible.
100 - * typically, JS or CSS
101 - **/
102 -function mailchimpSF_early_request_handler() {
103 - if (isset($_GET['mcsf_action'])) {
104 - switch ($_GET['mcsf_action']) {
105 - case 'main_css':
106 - header("Content-type: text/css");
107 - mailchimpSF_main_css();
108 - exit;
210 + // Backwards compatibility. TODO: Remove this in a future version.
211 + if ( get_option( 'mc_custom_style' ) === 'on' ) {
212 + $custom_css = mailchimp_sf_custom_style_css();
213 + wp_add_inline_style( 'mailchimp_sf_main_css', $custom_css );
109 214 }
110 215 }
111 216 }
112 -add_action('init', 'mailchimpSF_early_request_handler', 0);
113 217
114 218 /**
115 - * Outputs the front-end CSS. This checks several options, so it
116 - * was best to put it in a Request-handled script, as opposed to
117 - * a static file.
219 + * Custom styles CSS
220 + *
221 + * @return string
118 222 */
119 -function mailchimpSF_main_css() {
223 +function mailchimp_sf_custom_style_css() {
224 + ob_start();
120 225 ?>
121 - .mc_error_msg {
122 - color: red;
123 - }
124 - .mc_success_msg {
125 - color: green;
126 - }
127 - .mc_merge_var{
128 - padding:0;
129 - margin:0;
130 - }
131 -<?php
132 -// If we're utilizing custom styles
133 -if (get_option('mc_custom_style')=='on'){
134 - ?>
135 - #mc_signup_form {
226 + .mc_signup_form {
136 227 padding:5px;
137 - border-width: <?php echo get_option('mc_form_border_width'); ?>px;
138 - border-style: <?php echo (get_option('mc_form_border_width')==0) ? 'none' : 'solid'; ?>;
139 - border-color: #<?php echo get_option('mc_form_border_color'); ?>;
140 - color: #<?php echo get_option('mc_form_text_color'); ?>;
141 - background-color: #<?php echo get_option('mc_form_background'); ?>;
228 + border-width: <?php echo absint( get_option( 'mc_form_border_width' ) ); ?>px;
229 + border-style: <?php echo ( get_option( 'mc_form_border_width' ) === 0 ) ? 'none' : 'solid'; ?>;
230 + border-color: #<?php echo esc_attr( get_option( 'mc_form_border_color' ) ); ?>;
231 + color: #<?php echo esc_attr( get_option( 'mc_form_text_color' ) ); ?>;
232 + background-color: #<?php echo esc_attr( get_option( 'mc_form_background' ) ); ?>;
142 233 }
143 -
144 -
145 - .mc_custom_border_hdr {
146 - border-width: <?php echo get_option('mc_header_border_width'); ?>px;
147 - border-style: <?php echo (get_option('mc_header_border_width')==0) ? 'none' : 'solid'; ?>;
148 - border-color: #<?php echo get_option('mc_header_border_color'); ?>;
149 - color: #<?php echo get_option('mc_header_text_color'); ?>;
150 - background-color: #<?php echo get_option('mc_header_background'); ?>;
151 - font-size: 1.2em;
152 - padding:5px 10px;
153 - width: 100%;
154 - }
155 234 <?php
235 + return ob_get_clean();
156 236 }
157 -?>
158 - #mc_signup_container {}
159 - #mc_signup_form {}
160 - #mc_signup_form .mc_var_label {}
161 - #mc_signup_form .mc_input {}
162 - #mc-indicates-required {
163 - width:100%;
164 - }
165 - #mc_display_rewards {}
166 - #mc_interests_header {
167 - font-weight:bold;
168 - }
169 - div.mc_interest{
170 - width:100%;
171 - }
172 - #mc_signup_form input.mc_interest {}
173 - #mc_signup_form select {}
174 - #mc_signup_form label.mc_interest_label {
175 - display:inline;
176 - }
177 - .mc_signup_submit {
178 - text-align:center;
179 - }
180 - <?php
181 -}
182 237
183 -
184 238 /**
185 - * Add our settings page to the admin menu
239 + * Request handler
186 240 *
187 241 * @return void
188 242 */
189 -function mailchimpSF_add_pages(){
190 - // Add settings page for users who can edit plugins
191 - add_options_page( __( 'MailChimp Setup', 'mailchimp_i18n' ), __( 'MailChimp Setup', 'mailchimp_i18n' ), MCSF_CAP_THRESHOLD, 'mailchimpSF_options', 'mailchimpSF_setup_page');
192 -}
193 -add_action('admin_menu', 'mailchimpSF_add_pages');
194 -
195 -function mailchimpSF_request_handler() {
196 - if (isset($_POST['mcsf_action'])) {
197 - switch ($_POST['mcsf_action']) {
243 +function mailchimp_sf_request_handler() {
244 + if ( isset( $_POST['mcsf_action'] ) ) {
245 + switch ( $_POST['mcsf_action'] ) {
198 246 case 'logout':
199 247 // Check capability & Verify nonce
200 - if (!current_user_can(MCSF_CAP_THRESHOLD) || !wp_verify_nonce($_POST['_mcsf_nonce_action'], 'mc_logout')) {
201 - wp_die('Cheatin&rsquo; huh?');
248 + if (
249 + ! current_user_can( MCSF_CAP_THRESHOLD ) ||
250 + ! isset( $_POST['_mcsf_nonce_action'] ) ||
251 + ! wp_verify_nonce( sanitize_key( $_POST['_mcsf_nonce_action'] ), 'mc_logout' )
252 + ) {
253 + wp_die( 'Cheatin&rsquo; huh?' );
202 254 }
203 255
204 - // erase API Key
205 - update_option('mc_apikey', '');
256 + // erase auth information
257 + $options = array( 'mc_api_key', 'mailchimp_sf_access_token', 'mc_datacenter', 'mailchimp_sf_auth_error', 'mailchimp_sf_waiting_for_login' );
258 + mailchimp_sf_delete_options( $options );
206 259 break;
207 - case 'update_mc_apikey':
208 - // Check capability & Verify nonce
209 - if (!current_user_can(MCSF_CAP_THRESHOLD) || !wp_verify_nonce($_POST['_mcsf_nonce_action'], 'update_mc_api_key')) {
210 - wp_die('Cheatin&rsquo; huh?');
211 - }
212 -
213 - mailchimpSF_set_api_key(strip_tags(stripslashes($_POST['mc_apikey'])));
214 - break;
215 - case 'reset_list':
216 - // Check capability & Verify nonce
217 - if (!current_user_can(MCSF_CAP_THRESHOLD) || !wp_verify_nonce($_POST['_mcsf_nonce_action'], 'reset_mailchimp_list')) {
218 - wp_die('Cheatin&rsquo; huh?');
219 - }
220 -
221 - mailchimpSF_reset_list_settings();
222 - break;
223 260 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?');
261 + if (
262 + ! current_user_can( MCSF_CAP_THRESHOLD ) ||
263 + ! isset( $_POST['_mcsf_nonce_action'] ) ||
264 + ! wp_verify_nonce( sanitize_key( $_POST['_mcsf_nonce_action'] ), 'update_general_form_settings' )
265 + ) {
266 + wp_die( 'Cheatin&rsquo; huh?' );
226 267 }
227 -
268 +
228 269 // Update the form settings
229 - mailchimpSF_save_general_form_settings();
270 + mailchimp_sf_save_general_form_settings();
230 271 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 - /* Allow to fall through. The widget will pick up the
244 - * global message left over from the signup_submit function */
245 - break;
246 - case 'js':
247 - if (!headers_sent()){ //just in case...
248 - header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT', true, 200);
249 - }
250 - echo mailchimpSF_global_msg(); // Don't esc_html this, b/c we've already escaped it
251 - exit;
252 - }
253 272 }
254 273 }
255 274 }
256 -add_action('init', 'mailchimpSF_request_handler');
275 +add_action( 'init', 'mailchimp_sf_request_handler' );
257 276
277 +/**
278 + * Update merge fields
279 + *
280 + * @return void
281 + */
282 +function mailchimp_sf_update_merge_fields() {
283 + mailchimp_sf_get_merge_vars( get_option( 'mc_list_id' ), true );
284 + mailchimp_sf_get_interest_categories( get_option( 'mc_list_id' ), true );
285 + update_option( 'mc_merge_field_migrate', true );
286 +}
258 287
259 -
260 288 /**
261 - * Checks to see if we're storing a password, if so, we need
262 - * to upgrade to the API key
289 + * Get auth key
263 290 *
264 - * @return bool
265 - **/
266 -function mailchimpSF_needs_upgrade() {
267 - $ig = get_option('mc_interest_groups');
268 - return get_option('mc_show_interest_groups') == 'on' && (!is_array($ig['groups']) || !is_array($ig['groups'][0]));
291 + * @param mixed $salt Salt
292 + * @return string
293 + */
294 +function mailchimp_sf_auth_nonce_key( $salt = null ) {
295 + if ( is_null( $salt ) ) {
296 + $salt = mailchimp_sf_auth_nonce_salt();
297 + }
298 + return 'social_authentication' . md5( AUTH_KEY . $salt );
269 299 }
270 300
271 301 /**
272 - * MCAPIv1.2 -> MCAPIv1.3 - update interest groups
273 - * 2011-02-09 - old password upgrade code deleted as 0.5 is way old
302 + * Return auth nonce salt
303 + *
304 + * @return string
274 305 */
275 -function mailchimpSF_do_upgrade() {
276 - //left in just for good measure
277 - delete_option('mc_password');
278 - $api = new mailchimpSF_MCAPI(get_option('mc_apikey'));
279 - $ig = $api->listInterestGroupings(get_option('mc_list_id'));
280 - $ig = $ig[0];
281 - update_option('mc_interest_groups', $ig);
282 -
306 +function mailchimp_sf_auth_nonce_salt() {
307 + return md5( microtime() . isset( $_SERVER['SERVER_ADDR'] ) ? sanitize_text_field( wp_unslash( $_SERVER['SERVER_ADDR'] ) ) : '' );
283 308 }
284 309
285 310 /**
286 - * Sets the API Key to whatever value was passed to this func
311 + * Creates new Mailchimp API v3 object
287 312 *
288 - * @return array of vars
289 - **/
290 -function mailchimpSF_set_api_key($api_key = '') {
291 - $delete_setup = false;
292 - $api = new mailchimpSF_MCAPI($api_key);
293 - $api->ping();
294 - if (empty($api->errorCode)) {
295 - $msg = "<p class='success_msg'>".esc_html(__("Success! We were able to verify your API Key! Let's continue, shall we?", 'mailchimp_i18n'))."</p>";
296 - update_option('mc_apikey', $api_key);
297 - $req = $api->getAccountDetails();
298 - update_option('mc_username', $req['username']);
299 - update_option('mc_user_id', $req['user_id']);
300 - $cur_list_id = get_option('mc_list_id');
301 - if (!empty($cur_list_id)) {
302 - //we *could* support paging, but few users have that many lists (and shouldn't)
303 - $lists = $api->lists(array(),0,100);
304 - $lists = $lists['data'];
305 - //but don't delete if the list still exists...
306 - $delete_setup = true;
307 - foreach($lists as $list) {
308 - if ($list['id'] == $cur_list_id) {
309 - $list_id = $_POST['mc_list_id'];
310 - $delete_setup = false;
311 - }
312 - }
313 - }
314 - } else {
315 - $msg = "<p class='error_msg'>".esc_html(__('Uh-oh, we were unable to verify your API Key. Please check them and try again!', 'mailchimp_i18n'))."<br/>";
316 - $msg .= __('The server said:', 'mailchimp_i18n')."<em>".esc_html($api->errorMessage)."</em></p>";
317 - $username = get_option('mc_username');
318 - if (empty($username)) {
319 - $delete_setup = true;
320 - }
313 + * @return MailChimp_API | false
314 + */
315 +function mailchimp_sf_get_api() {
316 + // Check for the access token first.
317 + $access_token = mailchimp_sf_get_access_token();
318 + $data_center = get_option( 'mc_datacenter' );
319 + if ( ! empty( $access_token ) && ! empty( $data_center ) ) {
320 + return new MailChimp_API( $access_token, $data_center );
321 321 }
322 322
323 - // Set a global message
324 - mailchimpSF_global_msg($msg);
325 -
326 - // If we need to delete our setup, do it
327 - if ($delete_setup){
328 - mailchimpSF_delete_setup();
323 + // Check for the API key if the access token is not available.
324 + $key = get_option( 'mc_api_key' );
325 + if ( $key ) {
326 + return new MailChimp_API( $key );
329 327 }
330 -
331 - //set these for the form fields below
332 - $user = $_REQUEST['mc_username'];
333 -
334 - // return compact('user', 'delete_setup', 'list_id')
328 +
329 + return false;
335 330 }
336 331
337 332 /**
338 - * Deletes all mailchimp options
333 + * Checks to see if we're storing a password, if so, we need
334 + * to upgrade to the API key
335 + *
336 + * @return bool
339 337 **/
340 -function mailchimpSF_delete_setup() {
341 - delete_option('mc_user_id');
342 - delete_option('mc_rewards');
343 - delete_option('mc_use_javascript');
344 - delete_option('mc_use_unsub_link');
345 - delete_option('mc_list_id');
346 - delete_option('mc_list_name');
347 - delete_option('mc_interest_groups');
348 - delete_option('mc_show_interest_groups');
349 - $mv = get_option('mc_merge_vars');
350 - if (is_array($mv)){
351 - foreach($mv as $var){
352 - $opt = 'mc_mv_'.$var['tag'];
353 - delete_option($opt);
354 - }
355 - }
356 - delete_option('mc_merge_vars');
338 +function mailchimp_sf_needs_upgrade() {
339 + $igs = get_option( 'mc_interest_groups' );
340 +
341 + if ( false !== $igs // we have an option
342 + && (
343 + empty( $igs ) || // it can be an empty array (no interest groups)
344 + ( is_array( $igs ) && isset( $igs[0]['id'] ) ) // OR it should be a populated array that's well-formed
345 + )
346 + ) {
347 + return false; // no need to upgrade
348 + } else {
349 + return true; // yeah, let's do it
350 + }
357 351 }
358 352
359 353 /**
360 - * Resets the list settings, there's only one list
361 - * that can have settings at a time, so no list_id
362 - * parameter is necessary.
354 + * Deletes all Mailchimp options
355 + *
356 + * TODO: The options names should be moved to a config file
357 + * or to a class dedicated to options
363 358 **/
364 -function mailchimpSF_reset_list_settings() {
359 +function mailchimp_sf_delete_setup() {
360 + $options = array(
361 + 'mc_user_id',
362 + 'mc_use_unsub_link',
363 + 'mc_list_id',
364 + 'mc_list_name',
365 + 'mc_interest_groups',
366 + 'mc_merge_vars',
367 + );
365 368
366 - delete_option('mc_list_id');
367 - delete_option('mc_list_name');
368 - delete_option('mc_merge_vars');
369 - delete_option('mc_interest_groups');
369 + $igs = get_option( 'mc_interest_groups' );
370 + if ( is_array( $igs ) ) {
371 + foreach ( $igs as $ig ) {
372 + $opt = 'mc_show_interest_groups_' . $ig['id'];
373 + $options[] = $opt;
374 + }
375 + }
370 376
371 - delete_option('mc_use_javascript');
372 - delete_option('mc_use_unsub_link');
373 -
374 - delete_option('mc_header_content');
375 - delete_option('mc_subheader_content');
376 - delete_option('mc_submit_text');
377 + $mv = get_option( 'mc_merge_vars' );
378 + if ( is_array( $mv ) ) {
379 + foreach ( $mv as $mv_var ) {
380 + $opt = 'mc_mv_' . $mv_var['tag'];
381 + $options[] = $opt;
382 + }
383 + }
377 384
378 - delete_option('mc_custom_style');
379 -
380 - delete_option('mc_header_border_width');
381 - delete_option('mc_header_border_color');
382 - delete_option('mc_header_background');
383 - delete_option('mc_header_text_color');
384 -
385 - delete_option('mc_form_border_width');
386 - delete_option('mc_form_border_color');
387 - delete_option('mc_form_background');
388 - delete_option('mc_form_text_color');
389 -
390 - $msg = '<p class="success_msg">'.esc_html(__('Successfully Reset your List selection... Now you get to pick again!', 'mailchimp_i18n')).'</p>';
391 - mailchimpSF_global_msg($msg);
385 + mailchimp_sf_delete_options( $options );
392 386 }
393 387
394 388 /**
395 - * Gets or sets a global message based on parameter passed to it
389 + * Gets or sets a frontend message based on parameter passed to it
396 390 *
391 + * Used to convey error messages to the user outside of the WP Admin
392 + *
393 + * On the plugin settings page, WP admin notices are used exclusively
394 + * instead of the frontend message.
395 + *
396 + * @param mixed $msg Message
397 397 * @return string/bool depending on get/set
398 - **/
399 -function mailchimpSF_global_msg($msg = null) {
398 + */
399 +function mailchimp_sf_frontend_msg( $msg = null ) {
400 400 global $mcsf_msgs;
401 -
401 +
402 402 // Make sure we're formed properly
403 - if (!is_array($mcsf_msgs)) {
403 + if ( ! is_array( $mcsf_msgs ) ) {
404 404 $mcsf_msgs = array();
405 405 }
406 -
406 +
407 407 // See if we're getting
408 - if (is_null($msg)) {
409 - return implode('', $mcsf_msgs);
408 + if ( is_null( $msg ) ) {
409 + return implode( '', $mcsf_msgs );
410 410 }
411 411
412 412 // Must be setting
413 413 $mcsf_msgs[] = $msg;
@@ -414,28 +414,37 @@
414 414 return true;
415 415 }
416 416
417 417 /**
418 + * Gets or sets a frontend message based on parameter passed to it
419 + *
420 + * TODO: Deprecate this function in favor of mailchimp_sf_frontend_msg()
421 + *
422 + * @param mixed $msg Message
423 + * @return string/bool depending on get/set
424 + */
425 +function mailchimp_sf_global_msg( $msg = null ) {
426 + return mailchimp_sf_frontend_msg( $msg );
427 +}
428 +
429 +/**
418 430 * Sets the default options for the option form
419 - **/
420 -function mailchimpSF_set_form_defaults($list_name = '') {
421 - update_option('mc_header_content',__( 'Sign up for', 'mailchimp_i18n' ).' '.$list_name);
422 - update_option('mc_submit_text',__( 'Subscribe', 'mailchimp_i18n' ));
423 -
424 - update_option('mc_custom_style','on');
425 - update_option('mc_use_javascript','on');
426 - update_option('mc_use_unsub_link','off');
427 - update_option('mc_header_border_width','1');
428 - update_option('mc_header_border_color','E3E3E3');
429 - update_option('mc_header_background','FFFFFF');
430 - update_option('mc_header_text_color','CC6600');
431 -
432 - update_option('mc_form_border_width','1');
433 - update_option('mc_form_border_color','C4D3EA');
434 - update_option('mc_form_background','EEF3F8');
435 - update_option('mc_form_text_color','555555');
436 -
437 - update_option('mc_show_interest_groups', 'on' );
431 + *
432 + * @param string $list_name The Mailchimp list name.
433 + * @return void
434 + */
435 +function mailchimp_sf_set_form_defaults( $list_name = '' ) {
436 + update_option( 'mc_header_content', esc_html__( 'Sign up for', 'mailchimp' ) . ' ' . $list_name );
437 + update_option( 'mc_submit_text', esc_html__( 'Subscribe', 'mailchimp' ) );
438 +
439 + update_option( 'mc_custom_style', 'off' );
440 + update_option( 'mc_double_optin', true );
441 + update_option( 'mc_use_unsub_link', 'off' );
442 +
443 + update_option( 'mc_form_border_width', '1' );
444 + update_option( 'mc_form_border_color', 'E0E0E0' );
445 + update_option( 'mc_form_background', 'FFFFFF' );
446 + update_option( 'mc_form_text_color', '3F3F3f' );
438 447 }
439 448
440 449 /**
441 450 * Saves the General Form settings on the options page
@@ -441,725 +450,601 @@
441 450 * Saves the General Form settings on the options page
442 451 *
443 452 * @return void
444 453 **/
445 -function mailchimpSF_save_general_form_settings() {
446 - if (isset($_POST['mc_rewards'])){
447 - update_option('mc_rewards', 'on');
448 - $msg = '<p class="success_msg">'.__('Monkey Rewards turned On!', 'mailchimp_i18n').'</p>';
449 - mailchimpSF_global_msg($msg);
450 - } else if (get_option('mc_rewards')!='off') {
451 - update_option('mc_rewards', 'off');
452 - $msg = '<p class="success_msg">'.__('Monkey Rewards turned Off!', 'mailchimp_i18n').'</p>';
453 - mailchimpSF_global_msg($msg);
454 +function mailchimp_sf_save_general_form_settings() {
455 + // phpcs:disable WordPress.Security.NonceVerification.Missing -- Nonce check is already done in the mailchimp_sf_request_handler() function.
456 + /*Enable double optin toggle*/
457 + if ( isset( $_POST['mc_double_optin'] ) ) {
458 + update_option( 'mc_double_optin', true );
459 + $msg = esc_html__( 'Double opt-in turned On!', 'mailchimp' );
460 + admin_notice_success( $msg );
461 + } elseif ( get_option( 'mc_double_optin' ) !== false ) {
462 + update_option( 'mc_double_optin', false );
463 + $msg = esc_html__( 'Double opt-in turned Off!', 'mailchimp' );
464 + admin_notice_success( $msg );
454 465 }
455 - if (isset($_POST['mc_use_javascript'])){
456 - update_option('mc_use_javascript', 'on');
457 - $msg = '<p class="success_msg">'.__('Fancy Javascript submission turned On!', 'mailchimp_i18n').'</p>';
458 - mailchimpSF_global_msg($msg);
459 - } else if (get_option('mc_use_javascript')!='off') {
460 - update_option('mc_use_javascript', 'off');
461 - $msg = '<p class="success_msg">'.__('Fancy Javascript submission turned Off!', 'mailchimp_i18n').'</p>';
462 - mailchimpSF_global_msg($msg);
466 +
467 + /* NUKE the CSS! */
468 + if ( isset( $_POST['mc_nuke_all_styles'] ) ) {
469 + update_option( 'mc_nuke_all_styles', true );
470 + $msg = esc_html__( 'Mailchimp CSS turned Off!', 'mailchimp' );
471 + admin_notice_success( $msg );
472 + } elseif ( get_option( 'mc_nuke_all_styles' ) !== false ) {
473 + update_option( 'mc_nuke_all_styles', false );
474 + $msg = esc_html__( 'Mailchimp CSS turned On!', 'mailchimp' );
475 + admin_notice_success( $msg );
463 476 }
464 -
465 - if (isset($_POST['mc_use_unsub_link'])){
466 - update_option('mc_use_unsub_link', 'on');
467 - $msg = '<p class="success_msg">'.__('Unsubscribe link turned On!', 'mailchimp_i18n').'</p>';
468 - mailchimpSF_global_msg($msg);
469 - } else if (get_option('mc_use_unsub_link')!='off') {
470 - update_option('mc_use_unsub_link', 'off');
471 - $msg = '<p class="success_msg">'.__('Unsubscribe link turned Off!', 'mailchimp_i18n').'</p>';
472 - mailchimpSF_global_msg($msg);
477 +
478 + /* Update existing */
479 + if ( isset( $_POST['mc_update_existing'] ) ) {
480 + update_option( 'mc_update_existing', true );
481 + $msg = esc_html__( 'Update existing subscribers turned On!', 'mailchimp' );
482 + admin_notice_success( $msg );
483 + } elseif ( get_option( 'mc_update_existing' ) !== false ) {
484 + update_option( 'mc_update_existing', false );
485 + $msg = esc_html__( 'Update existing subscribers turned Off!', 'mailchimp' );
486 + admin_notice_success( $msg );
473 487 }
474 488
475 - $content = stripslashes($_POST['mc_header_content']);
476 - $content = str_replace("\r\n","<br/>", $content);
477 - update_option('mc_header_content', $content );
478 -
479 - $content = stripslashes($_POST['mc_subheader_content']);
480 - $content = str_replace("\r\n","<br/>", $content);
481 - update_option('mc_subheader_content', $content );
489 + if ( isset( $_POST['mc_use_unsub_link'] ) ) {
490 + update_option( 'mc_use_unsub_link', 'on' );
491 + $msg = esc_html__( 'Unsubscribe link turned On!', 'mailchimp' );
492 + admin_notice_success( $msg );
493 + } elseif ( get_option( 'mc_use_unsub_link' ) !== 'off' ) {
494 + update_option( 'mc_use_unsub_link', 'off' );
495 + $msg = esc_html__( 'Unsubscribe link turned Off!', 'mailchimp' );
496 + admin_notice_success( $msg );
497 + }
482 498
499 + $content = isset( $_POST['mc_header_content'] ) ? wp_kses_post( wp_unslash( $_POST['mc_header_content'] ) ) : '';
500 + $content = str_replace( "\r\n", '<br/>', $content );
501 + update_option( 'mc_header_content', $content );
483 502
484 - $submit_text = stripslashes($_POST['mc_submit_text']);
485 - $submit_text = str_replace("\r\n","", $submit_text);
486 - update_option('mc_submit_text', $submit_text);
487 -
503 + $content = isset( $_POST['mc_subheader_content'] ) ? wp_kses_post( wp_unslash( $_POST['mc_subheader_content'] ) ) : '';
504 + $content = str_replace( "\r\n", '<br/>', $content );
505 + update_option( 'mc_subheader_content', $content );
506 +
507 + $submit_text = isset( $_POST['mc_submit_text'] ) ? sanitize_text_field( wp_unslash( $_POST['mc_submit_text'] ) ) : '';
508 + $submit_text = str_replace( "\r\n", '', $submit_text );
509 + update_option( 'mc_submit_text', $submit_text );
510 +
488 511 // Set Custom Style option
489 - update_option('mc_custom_style', (isset($_POST['mc_custom_style'])) ? 'on' : 'off');
512 + update_option( 'mc_custom_style', isset( $_POST['mc_custom_style'] ) ? 'on' : 'off' );
490 513
491 - //we told them not to put these things we are replacing in, but let's just make sure they are listening...
492 - update_option('mc_header_border_width',str_replace('px','',$_POST['mc_header_border_width']) );
493 - update_option('mc_header_border_color', str_replace('#','',$_POST['mc_header_border_color']));
494 - update_option('mc_header_background',str_replace('#','',$_POST['mc_header_background']));
495 - update_option('mc_header_text_color', str_replace('#','',$_POST['mc_header_text_color']));
514 + // we told them not to put these things we are replacing in, but let's just make sure they are listening...
515 + if ( isset( $_POST['mc_form_border_width'] ) ) {
516 + update_option( 'mc_form_border_width', str_replace( 'px', '', absint( $_POST['mc_form_border_width'] ) ) );
517 + }
518 + if ( isset( $_POST['mc_form_border_color'] ) ) {
519 + update_option( 'mc_form_border_color', str_replace( '#', '', sanitize_text_field( wp_unslash( $_POST['mc_form_border_color'] ) ) ) );
520 + }
521 + if ( isset( $_POST['mc_form_background'] ) ) {
522 + update_option( 'mc_form_background', str_replace( '#', '', sanitize_text_field( wp_unslash( $_POST['mc_form_background'] ) ) ) );
523 + }
524 + if ( isset( $_POST['mc_form_text_color'] ) ) {
525 + update_option( 'mc_form_text_color', str_replace( '#', '', sanitize_text_field( wp_unslash( $_POST['mc_form_text_color'] ) ) ) );
526 + }
496 527
497 - update_option('mc_form_border_width',str_replace('px','',$_POST['mc_form_border_width']) );
498 - update_option('mc_form_border_color', str_replace('#','',$_POST['mc_form_border_color']));
499 - update_option('mc_form_background',str_replace('#','',$_POST['mc_form_background']));
500 - update_option('mc_form_text_color', str_replace('#','',$_POST['mc_form_text_color']));
528 + // IF NOT DEV MODE
529 + $igs = get_option( 'mc_interest_groups' );
530 + if ( is_array( $igs ) ) {
531 + foreach ( $igs as $mv_var ) {
532 + $opt = 'mc_show_interest_groups_' . $mv_var['id'];
533 + if ( isset( $_POST[ $opt ] ) ) {
534 + update_option( $opt, 'on' );
535 + } else {
536 + update_option( $opt, 'off' );
537 + }
538 + }
539 + }
501 540
502 - update_option('mc_show_interest_groups', (isset($_POST['mc_show_interest_groups'])) ? 'on' : 'off');
503 -
504 - $mv = get_option('mc_merge_vars');
505 - if (is_array($mv)) {
506 - foreach($mv as $var){
507 - $opt = 'mc_mv_'.$var['tag'];
508 - if (isset($_POST[$opt]) || $var['req']=='Y'){
509 - update_option($opt,'on');
541 + $mv = get_option( 'mc_merge_vars' );
542 + if ( is_array( $mv ) ) {
543 + foreach ( $mv as $mv_var ) {
544 + $opt = 'mc_mv_' . $mv_var['tag'];
545 + if ( isset( $_POST[ $opt ] ) || true === (bool) $mv_var['required'] ) {
546 + update_option( $opt, 'on' );
510 547 } else {
511 - update_option($opt,'off');
548 + update_option( $opt, 'off' );
512 549 }
513 550 }
514 551 }
515 - $msg = '<p class="success_msg">'.esc_html(__('Successfully Updated your List Subscribe Form Settings!', 'mailchimp_i18n')).'</p>';
516 - mailchimpSF_global_msg($msg);
552 +
553 + $msg = esc_html__( 'Successfully Updated your List Subscribe Form Settings!', 'mailchimp' );
554 + admin_notice_success( $msg );
555 + // phpcs:enable WordPress.Security.NonceVerification.Missing
517 556 }
518 557
519 558 /**
520 559 * Sees if the user changed the list, and updates options accordingly
521 560 **/
522 -function mailchimpSF_change_list_if_necessary($api_key) {
523 - // Simple permission check before going through all this
524 - if (!current_user_can(MCSF_CAP_THRESHOLD)) { return; }
525 -
526 - $api = new mailchimpSF_MCAPI($api_key);
527 - //we *could* support paging, but few users have that many lists (and shouldn't)
528 - $lists = $api->lists(array(),0,100);
529 - $lists = $lists['data'];
530 -
531 - /* If our incoming list ID (the one chosen in the select dropdown)
532 - is in our array of lists, the set it to be the active list */
533 - foreach($lists as $list) {
534 - if ($list['id'] == $_POST['mc_list_id']) {
535 - $list_id = $_POST['mc_list_id'];
536 - $list_name = $list['name'];
537 - }
561 +function mailchimp_sf_change_list_if_necessary() {
562 + if ( ! isset( $_POST['mc_list_id'] ) ) {
563 + return;
538 564 }
539 -
540 - $orig_list = get_option('mc_list_id');
541 - if ($list_id != '') {
542 - update_option('mc_list_id', $list_id);
543 - update_option('mc_list_name', $list_name);
544 -
545 - // See if the user changed the list
546 - if ($orig_list != $list_id){
547 - // The user changed the list, Reset the Form Defaults
548 - mailchimpSF_set_form_defaults($list_name);
549 - }
550 -
551 - // Grab the merge vars and interest groups
552 - $mv = $api->listMergeVars($list_id);
553 - $ig = $api->listInterestGroupings($list_id);
554 - $ig = $ig[0];
555 - update_option('mc_merge_vars', $mv);
556 - foreach($mv as $var){
557 - $opt = 'mc_mv_'.$var['tag'];
558 - //turn them all on by default
559 - if ($orig_list != $list_id){
560 - update_option($opt, 'on' );
561 - }
562 - }
563 - update_option('mc_interest_groups', $ig);
564 565
565 - $msg = '<p class="success_msg">'.
566 - sprintf(
567 - __('Success! Loaded and saved the info for %d Merge Variables and %d Interest Groups from your list', 'mailchimp_i18n'),
568 - count($mv),
569 - count($ig['groups'])
570 - ).
571 - ' "'.$list_name.'"<br/><br/>'.
572 - __('Now you should either Turn On the MailChimp Widget or change your options below, then turn it on.', 'mailchimp_i18n').'</p>';
573 - mailchimpSF_global_msg($msg);
566 + if (
567 + ! current_user_can( MCSF_CAP_THRESHOLD ) ||
568 + ! isset( $_POST['update_mc_list_id_nonce'] ) ||
569 + ! wp_verify_nonce( sanitize_key( $_POST['update_mc_list_id_nonce'] ), 'update_mc_list_id_action' )
570 + ) {
571 + wp_die( 'Security check failed.' );
574 572 }
575 -}
576 573
577 -/**
578 - * Outputs the Settings/Options page
579 - */
580 -function mailchimpSF_setup_page() {
574 + if ( empty( $_POST['mc_list_id'] ) ) {
575 + $msg = esc_html__( 'Please choose a valid list', 'mailchimp' );
576 + admin_notice_error( $msg );
577 + return;
578 + }
581 579
582 -// See if we need an upgrade
583 -if (mailchimpSF_needs_upgrade()) {
584 - // remove password option if it's set
585 - mailchimpSF_do_upgrade();
586 -}
580 + $lists = mailchimp_sf_get_lists();
581 + if ( is_wp_error( $lists ) || ! isset( $lists['lists'] ) ) {
582 + return;
583 + }
587 584
588 -?>
589 -<div class="wrap">
585 + $lists = $lists['lists'];
590 586
591 - <h2><?php esc_html_e('MailChimp List Setup', 'mailchimp_i18n');?> </h2>
587 + if ( is_array( $lists ) && ! empty( $lists ) ) {
592 588
593 -<?php
589 + /**
590 + * If our incoming list ID (the one chosen in the select dropdown)
591 + * is in our array of lists, the set it to be the active list
592 + */
593 + foreach ( $lists as $key => $list ) {
594 + if ( isset( $_POST['mc_list_id'] ) && $list['id'] === $_POST['mc_list_id'] ) {
595 + $list_id = sanitize_text_field( wp_unslash( $_POST['mc_list_id'] ) );
596 + $list_name = $list['name'];
597 + $list_key = $key;
598 + }
594 599
595 -$user = get_option('mc_username');
596 -$api_key = get_option('mc_apikey');
600 + $merge_fields = mailchimp_sf_get_merge_vars( $list['id'], false, false );
601 + $interests = mailchimp_sf_get_interest_categories( $list['id'], false, false );
602 + if ( ! empty( $merge_fields ) ) {
603 + update_option( 'mailchimp_sf_merge_fields_' . $list['id'], $merge_fields );
604 + }
605 + if ( ! empty( $interests ) ) {
606 + update_option( 'mailchimp_sf_interest_groups_' . $list['id'], $interests );
607 + }
608 + }
597 609
598 -// If we have an API Key, see if we need to change the lists and its options
599 -if (!empty($api_key)){
600 - mailchimpSF_change_list_if_necessary($api_key);
601 -}
610 + $orig_list = get_option( 'mc_list_id' );
611 + if ( '' !== $list_id ) {
612 + update_option( 'mc_list_id', $list_id );
613 + update_option( 'mc_list_name', $list_name );
614 + update_option( 'mc_email_type_option', $lists[ $list_key ]['email_type_option'] );
602 615
616 + // See if the user changed the list
617 + $new_list = false;
618 + if ( $orig_list !== $list_id ) {
619 + // The user changed the list, Reset the Form Defaults
620 + mailchimp_sf_set_form_defaults( $list_name );
603 621
622 + $new_list = true;
623 + }
604 624
605 -// Display our success/error message(s) if have them
606 -if (mailchimpSF_global_msg() != ''){
607 - // Message has already been html escaped, so we don't want to 2x escape it here
608 - ?>
609 - <div id="mc_message" class=""><?php echo mailchimpSF_global_msg(); ?></div>
610 - <?php
611 -}
625 + // Grab the merge vars and interest groups
626 + $mv = mailchimp_sf_get_merge_vars( $list_id, $new_list );
627 + $igs = mailchimp_sf_get_interest_categories( $list_id, $new_list );
612 628
629 + $igs_text = ' ';
630 + if ( is_array( $igs ) ) {
631 + /* translators: %s: count (number) */
632 + $igs_text .= sprintf( esc_html__( 'and %s Sets of Interest Groups', 'mailchimp' ), count( $igs ) );
633 + }
613 634
614 -// If we don't have an API Key, do a login form
615 -if (get_option('mc_apikey') == '') {
616 - ?>
617 - <div>
618 - <form method="post" action="options-general.php?page=mailchimpSF_options">
619 - <h3><?php esc_html_e('Login Info', 'mailchimp_i18n');?></h3>
620 - <?php esc_html_e('To start using the MailChimp plugin, we first need to login and get your API Key. Please enter your MailChimp API Key below.', 'mailchimp_i18n'); ?>
621 -
622 - <br/>
623 -
624 - <?php
625 - echo sprintf(
626 - '%1$s <a href="http://www.mailchimp.com/signup/" target="_blank">%2$s</a>',
627 - esc_html(__("Don't have a MailChimp account?", 'mailchimp_i18n')),
628 - esc_html(__('Try one for Free!', 'mailchimp_i18n'))
629 - );
630 - ?>
631 -
632 - <br/>
633 -
634 - <table class="form-table">
635 - <tr valign="top">
636 - <th scope="row"><?php esc_html_e('API Key', 'mailchimp_i18n'); ?>:</th>
637 - <td>
638 - <input name="mc_apikey" type="text" id="mc_apikey" class="code" value="<?php echo esc_attr($apikey); ?>" size="32" />
639 - <br/>
640 - <a href="http://admin.mailchimp.com/account/api-key-popup" target="_blank">get your API Key here</a>
641 - </td>
642 - </tr>
643 - </table>
644 -
645 - <input type="hidden" name="mcsf_action" value="update_mc_apikey"/>
646 - <input type="submit" name="Submit" value="<?php esc_attr_e('Save & Check', 'mailchimp_i18n');?>" class="button" />
647 - <?php wp_nonce_field('update_mc_api_key', '_mcsf_nonce_action'); ?>
648 - </form>
649 - </div>
635 + $msg = sprintf(
636 + /* translators: %s: count (number) */
637 + __( '<b>Success!</b> Loaded and saved the info for %d Merge Variables', 'mailchimp' ) . $igs_text,
638 + count( $mv )
639 + ) . ' ' .
640 + esc_html__( 'from your list', 'mailchimp' ) . ' "' . $list_name . '"<br/><br/>' .
641 + esc_html__( 'Now you should either Turn On the Mailchimp Widget or change your options below, then turn it on.', 'mailchimp' );
650 642
651 - <?php
652 - if (get_option('mc_username')!=''){
653 - ?>
654 - <strong><?php esc_html_e('Notes', 'mailchimp_i18n'); ?>:</strong>
655 - <ul>
656 - <li><em><?php esc_html_e('Changing your settings at MailChimp.com may cause this to stop working.', 'mailchimp_i18n'); ?></em></li>
657 - <li><em><?php esc_html_e('If you change your login to a different account, the info you have setup below will be erased.', 'mailchimp_i18n'); ?></em></li>
658 - <li><em><?php esc_html_e('If any of that happens, no biggie - just reconfigure your login and the items below...', 'mailchimp_i18n'); ?></em></li>
659 - </ul>
660 - <br/>
661 - <?php
662 - }
663 -} // End of login form
643 + admin_notice_success( $msg );
644 + }
664 645
665 -// Start logout form
666 -else {
667 -?>
668 -<table style="min-width:400px;">
669 - <tr>
670 - <td><h3><?php esc_html_e('Logged in as', 'mailchimp_i18n');?>: <?php echo esc_html(get_option('mc_username')); ?></h3>
671 - </td>
672 - <td>
673 - <form method="post" action="options-general.php?page=mailchimpSF_options">
674 - <input type="hidden" name="mcsf_action" value="logout"/>
675 - <input type="submit" name="Submit" value="<?php esc_attr_e('Logout', 'mailchimp_i18n');?>" class="button" />
676 - <?php wp_nonce_field('mc_logout', '_mcsf_nonce_action'); ?>
677 - </form>
678 - </td>
679 - </tr>
680 -</table>
681 -<?php
682 -} // End Logout form
646 + // Update the lists option.
647 + update_option( 'mailchimp_sf_lists', $lists );
648 + }
649 +}
683 650
651 +/**
652 + * Get merge vars
653 + *
654 + * @param string $list_id List ID
655 + * @param bool $new_list Whether this is a new list
656 + * @param bool $update_option Whether to update the option
657 + * @return array
658 + */
659 +function mailchimp_sf_get_merge_vars( $list_id, $new_list, $update_option = true ) {
660 + $api = mailchimp_sf_get_api();
661 + $mv = $api->get( 'lists/' . $list_id . '/merge-fields', 80 );
684 662
663 + // if we get an error back from the api, exit this process.
664 + if ( is_wp_error( $mv ) ) {
665 + return;
666 + }
685 667
686 -//Just get out if nothing else matters...
687 -if (get_option('mc_apikey') == '') return;
668 + $mv['merge_fields'] = mailchimp_sf_add_email_field( $mv['merge_fields'] );
669 + if ( $update_option ) {
670 + update_option( 'mc_merge_vars', $mv['merge_fields'] );
671 + }
688 672
689 -if (get_option('mc_apikey')!=''){
690 - ?>
691 - <h3><?php esc_html_e('Your Lists', 'mailchimp_i18n'); ?></h3>
692 -
693 -<div>
694 -
695 - <p><?php esc_html_e('Please select the List you wish to create a Signup Form for.', 'mailchimp_i18n'); ?></p>
696 -
697 - <form method="post" action="options-general.php?page=mailchimpSF_options">
698 - <?php
699 - $api = new mailchimpSF_MCAPI(get_option('mc_apikey'));
700 - //we *could* support paging, but few users have that many lists (and shouldn't)
701 - $lists = $api->lists(array(),0,100);
702 - $lists = $lists['data'];
703 -
704 - if (count($lists) == 0) {
705 - ?>
706 - <span class='error_msg'>
707 - <?php
708 - echo sprintf(
709 - esc_html(__("Uh-oh, you don't have any lists defined! Please visit %s, login, and setup a list before using this tool!", 'mailchimp_i18n')),
710 - "<a href='http://www.mailchimp.com/'>MailChimp</a>"
711 - );
712 - ?>
713 - </span>
714 - <?php
673 + foreach ( $mv['merge_fields'] as $mv_var ) {
674 + $opt = 'mc_mv_' . $mv_var['tag'];
675 + if ( $new_list ) {
676 + $public = $mv_var['public'] ?? false;
677 + if ( ! $public ) {
678 + // This is a hidden field, so we don't want to include it.
679 + update_option( $opt, 'off' );
680 + } else {
681 + // We need to set the option to 'on' so that it shows up in the form.
682 + update_option( $opt, 'on' );
683 + }
715 684 }
716 - else {
717 - ?>
718 - <table style="min-width:400px">
719 - <tr>
720 - <td>
721 - <select name="mc_list_id" style="min-width:200px;">
722 - <option value=""> &mdash; <?php esc_html_e('Select A List','mailchimp_i18n'); ?> &mdash; </option>
723 - <?php
724 - foreach ($lists as $list) {
725 - $option = get_option('mc_list_id');
726 - ?>
727 - <option value="<?php echo esc_attr($list['id']); ?>"<?php selected($list['id'], $option); ?>><?php echo esc_html($list['name']); ?></option>
728 - <?php
729 - }
730 - ?>
731 - </select>
732 - </td>
733 - <td>
734 - <input type="hidden" name="mcsf_action" value="update_mc_list_id" />
735 - <input type="submit" name="Submit" value="<?php esc_attr_e('Update List', 'mailchimp_i18n'); ?>" class="button" />
736 - </td>
737 - </tr>
738 - <tr>
739 - <td colspan="2">
740 - <strong><?php esc_html_e('Note:', 'mailchimp_i18n'); ?></strong> <em><?php esc_html_e('Updating your list will not cause settings below to be lost. Changing to a new list will.', 'mailchimp_i18n'); ?></em>
741 - </td>
742 - </tr>
743 - </table>
744 - <?php
745 - } //end select list
746 - ?>
747 - </form>
748 -</div>
685 + }
686 + return $mv['merge_fields'];
687 +}
749 688
750 -<br/>
751 -
752 -<?php
753 -}
754 -else {
755 -//display the selected list...
756 -?>
757 -
758 -<p class="submit">
759 - <form method="post" action="options-general.php?page=mailchimpSF_options">
760 - <input type="hidden" name="mcsf_action" value="reset_list" />
761 - <input type="submit" name="reset_list" value="<?php esc_attr_e('Reset List Options and Select again', 'mailchimp_i18n'); ?>" class="button" />
762 - <?php wp_nonce_field('reset_mailchimp_list', '_mcsf_nonce_action'); ?>
763 - </form>
764 -</p>
765 -<h3><?php esc_html_e('Subscribe Form Widget Settings for this List', 'mailchimp_i18n'); ?>:</h3>
766 -<h4><?php esc_html_e('Selected MailChimp List', 'mailchimp_i18n'); ?>: <?php echo esc_html(get_option('mc_list_name')); ?></h4>
767 -<?php
689 +/**
690 + * Add email field
691 + *
692 + * @param array $merge Merge
693 + * @return array
694 + */
695 +function mailchimp_sf_add_email_field( $merge ) {
696 + $email = array(
697 + 'tag' => 'EMAIL',
698 + 'name' => esc_html__( 'Email Address', 'mailchimp' ),
699 + 'type' => 'email',
700 + 'required' => true,
701 + 'public' => true,
702 + 'display_order' => 1,
703 + 'default_value' => null,
704 + );
705 + array_unshift( $merge, $email );
706 + return $merge;
768 707 }
769 -//Just get out if nothing else matters...
770 -if (get_option('mc_list_id') == '') return;
771 708
709 +/**
710 + * Get interest categories
711 + *
712 + * @param string $list_id List ID
713 + * @param bool $new_list Whether this is a new list
714 + * @param bool $update_option Whether to update the option
715 + * @return array
716 + */
717 +function mailchimp_sf_get_interest_categories( $list_id, $new_list, $update_option = true ) {
718 + $api = mailchimp_sf_get_api();
719 + $igs = $api->get( 'lists/' . $list_id . '/interest-categories', 60 );
772 720
773 -// The main Settings form
774 -?>
721 + // if we get an error back from the api, exis
722 + if ( is_wp_error( $igs ) ) {
723 + return;
724 + }
775 725
776 -<div>
777 -<form method="post" action="options-general.php?page=mailchimpSF_options">
778 -<div style="width:600px;">
779 -<input type="hidden" name="mcsf_action" value="change_form_settings">
780 -<?php wp_nonce_field('update_general_form_settings', '_mcsf_nonce_action'); ?>
781 -<input type="submit" value="<?php esc_attr_e('Update Subscribe Form Settings', 'mailchimp_i18n'); ?>" class="button" />
782 -<table class="widefat">
783 - <tr valign="top">
784 - <th scope="row"><?php esc_html_e('Monkey Rewards', 'mailchimp_i18n'); ?>:</th>
785 - <td><input name="mc_rewards" type="checkbox"<?php if (get_option('mc_rewards')=='on' || get_option('mc_rewards')=='' ) { echo ' checked="checked"'; } ?> id="mc_rewards" class="code" />
786 - <em><label for="mc_rewards"><?php esc_html_e('turning this on will place a "powered by MailChimp" link in your form that will earn you credits with us. It is optional and can be turned on or off at any time.', 'mailchimp_i18n'); ?></label></em>
787 - </td>
788 - </tr>
789 - <tr valign="top">
790 - <th scope="row"><?php esc_html_e('Use Javascript Support?', 'mailchimp_i18n'); ?>:</th>
791 - <td><input name="mc_use_javascript" type="checkbox" <?php checked(get_option('mc_use_javascript'), 'on'); ?> id="mc_use_javascript" class="code" />
792 - <em><label for="mc_use_javascript"><?php esc_html_e('turning this on will use fancy javascript submission and should degrade gracefully for users not using javascript. It is optional and can be turned on or off at any time.', 'mailchimp_i18n'); ?></label></em>
793 - </td>
794 - </tr>
795 - <tr valign="top">
796 - <th scope="row"><?php esc_html_e('Include Unsubscribe link?', 'mailchimp_i18n'); ?>:</th>
797 - <td><input name="mc_use_unsub_link" type="checkbox"<?php checked(get_option('mc_use_unsub_link'), 'on'); ?> id="mc_use_unsub_link" class="code" />
798 - <em><label for="mc_use_unsub_link"><?php esc_html_e('turning this on will add a link to your host unsubscribe form', 'mailchimp_i18n'); ?></label></em>
799 - </td>
800 - </tr>
801 - <tr valign="top">
802 - <th scope="row"><?php esc_html_e('Header content', 'mailchimp_i18n'); ?>:</th>
803 - <td>
804 - <textarea name="mc_header_content" rows="2" cols="50"><?php echo esc_html(get_option('mc_header_content')); ?></textarea><br/>
805 - <em><?php esc_html_e('You can fill this with your own Text, HTML markup (including image links), or Nothing!', 'mailchimp_i18n'); ?></em>
806 - </td>
807 - </tr>
808 -
809 - <tr valign="top">
810 - <th scope="row"><?php esc_html_e('Sub-header content', 'mailchimp_i18n'); ?>:</th>
811 - <td>
812 - <textarea name="mc_subheader_content" rows="2" cols="50"><?php echo esc_html(get_option('mc_subheader_content')); ?></textarea><br/>
813 - <em><?php esc_html_e('You can fill this with your own Text, HTML markup (including image links), or Nothing!', 'mailchimp_i18n'); ?></em>.
814 - <?php esc_html_e('This will be displayed under the heading and above the form.', 'mailchimp_i18n'); ?>
815 - </td>
816 - </tr>
726 + if ( is_array( $igs ) ) {
727 + $key = 0;
728 + foreach ( $igs['categories'] as $ig ) {
729 + $groups = $api->get( 'lists/' . $list_id . '/interest-categories/' . $ig['id'] . '/interests', 60 );
730 + $igs['categories'][ $key ]['groups'] = $groups['interests'];
731 + $opt = 'mc_show_interest_groups_' . $ig['id'];
817 732
733 + // turn them all on by default
734 + if ( $new_list ) {
735 + update_option( $opt, 'on' );
736 + }
737 + ++$key;
738 + }
739 + }
818 740
819 - <tr valign="top">
820 - <th scope="row"><?php esc_html_e('Submit Button text', 'mailchimp_i18n'); ?>:</th>
821 - <td>
822 - <input type="text" name="mc_submit_text" size="30" value="<?php echo esc_attr(get_option('mc_submit_text')); ?>"/>
823 - </td>
824 - </tr>
741 + if ( $update_option ) {
742 + update_option( 'mc_interest_groups', $igs['categories'] );
743 + }
825 744
826 - <tr valign="top">
827 - <th scope="row"><?php esc_html_e('Custom Styling', 'mailchimp_i18n'); ?>:</th>
828 - <td>
829 - <table class="widefat">
745 + return $igs['categories'];
746 +}
830 747
831 - <tr><th><label for="mc_custom_style"><?php esc_html_e('Turned On?', 'mailchimp_i18n'); ?></label></th><td><input type="checkbox" name="mc_custom_style" id="mc_custom_style"<?php checked(get_option('mc_custom_style'), 'on'); ?> /></td></tr>
832 - <tr><th colspan="2"><?php esc_html_e('Header Settings (only applies if there are no HTML tags in the Header Content area above)', 'mailchimp_i18n'); ?>:</th></tr>
833 - <tr><th><?php esc_html_e('Border Width', 'mailchimp_i18n'); ?>:</th><td><input type="text" name="mc_header_border_width" size="3" maxlength="3" value="<?php echo esc_attr(get_option('mc_header_border_width')); ?>"/> px<br/>
834 - <em><?php esc_html_e('Set to 0 for no border, do not enter', 'mailchimp_i18n'); ?> <strong>px</strong>!</em>
835 - </td></tr>
836 - <tr><th><?php esc_html_e('Border Color', 'mailchimp_i18n'); ?>:</th><td>#<input type="text" name="mc_header_border_color" size="7" maxlength="6" value="<?php echo esc_attr(get_option('mc_header_border_color')); ?>"/><br/>
837 - <em><?php esc_html_e('do not enter initial', 'mailchimp_i18n'); ?> <strong>#</strong></em>
838 - </td></tr>
839 - <tr><th><?php esc_html_e('Text Color', 'mailchimp_i18n'); ?>:</th><td>#<input type="text" name="mc_header_text_color" size="7" maxlength="6" value="<?php echo esc_attr(get_option('mc_header_text_color')); ?>"/><br/>
840 - <em><?php esc_html_e('do not enter initial', 'mailchimp_i18n'); ?> <strong>#</strong></em>
841 - </td></tr>
842 - <tr><th><?php esc_html_e('Background Color', 'mailchimp_i18n'); ?>:</th><td>#<input type="text" name="mc_header_background" size="7" maxlength="6" value="<?php echo esc_attr(get_option('mc_header_background')); ?>"/><br/>
843 - <em><?php esc_html_e('do not enter initial', 'mailchimp_i18n'); ?> <strong>#</strong></em>
844 - </td></tr>
845 -
846 - <tr><th colspan="2"><?php esc_html_e('Form Settings', 'mailchimp_i18n'); ?>:</th></tr>
847 - <tr><th><?php esc_html_e('Border Width', 'mailchimp_i18n'); ?>:</th><td><input type="text" name="mc_form_border_width" size="3" maxlength="3" value="<?php echo esc_attr(get_option('mc_form_border_width')); ?>"/> px<br/>
848 - <em><?php esc_html_e('Set to 0 for no border, do not enter', 'mailchimp_i18n'); ?> <strong>px</strong>!</em>
849 - </td></tr>
850 - <tr><th><?php esc_html_e('Border Color', 'mailchimp_i18n'); ?>:</th><td>#<input type="text" name="mc_form_border_color" size="7" maxlength="6" value="<?php echo esc_attr(get_option('mc_form_border_color')); ?>"/><br/>
851 - <em><?php esc_html_e('do not enter initial', 'mailchimp_i18n'); ?> <strong>#</strong></em>
852 - </td></tr>
853 - <tr><th><?php esc_html_e('Text Color', 'mailchimp_i18n'); ?>:</th><td>#<input type="text" name="mc_form_text_color" size="7" maxlength="6" value="<?php echo esc_attr(get_option('mc_form_text_color')); ?>"/><br/>
854 - <em><?php esc_html_e('do not enter initial', 'mailchimp_i18n'); ?> <strong>#</strong></em>
855 - </td></tr>
856 - <tr><th><?php esc_html_e('Background Color', 'mailchimp_i18n'); ?>:</th><td>#<input type="text" name="mc_form_background" size="7" maxlength="6" value="<?php echo esc_attr(get_option('mc_form_background')); ?>"/><br/>
857 - <em><?php esc_html_e('do not enter initial', 'mailchimp_i18n'); ?> <strong>#</strong></em>
858 - </td></tr>
859 - </table>
860 -</td>
861 -</tr>
862 -</table>
863 -</div>
864 -<input type="submit" value="<?php esc_attr_e('Update Subscribe Form Settings', 'mailchimp_i18n'); ?>" class="button" />
865 -
866 -<?php
867 -// Merge Variables Table
868 -?>
869 -<div style="width:400px;">
870 -
871 -<h4><?php esc_html_e('Merge Variables Included', 'mailchimp_i18n'); ?></h4>
872 -
873 -<?php
874 -$mv = get_option('mc_merge_vars');
875 -
876 -if (count($mv) == 0 || !is_array($mv)){
877 - ?>
878 - <em><?php esc_html_e('No Merge Variables found.', 'mailchimp_i18n'); ?></em>
879 - <?php
880 -} else {
881 - ?>
882 -
883 - <table class='widefat'>
884 - <tr valign="top">
885 - <th><?php esc_html_e('Name', 'mailchimp_i18n');?></th>
886 - <th><?php esc_html_e('Tag', 'mailchimp_i18n');?></th>
887 - <th><?php esc_html_e('Required?', 'mailchimp_i18n');?></th>
888 - <th><?php esc_html_e('Include?', 'mailchimp_i18n');?></th>
889 - </tr>
890 - <?php
891 - foreach($mv as $var){
892 - ?>
893 - <tr valign="top">
894 - <td><?php echo esc_html($var['name']); ?></td>
895 - <td><?php echo esc_html($var['tag']); ?></td>
896 - <td><?php echo esc_html(($var['req'] == 1) ? 'Y' : 'N'); ?></td>
897 - <td>
898 - <?php
899 - if (!$var['req']){
900 - $opt = 'mc_mv_'.$var['tag'];
901 - ?>
902 - <input name="<?php echo esc_attr($opt); ?>" type="checkbox" id="<?php echo esc_attr($opt); ?>" class="code"<?php checked(get_option($opt), 'on'); ?> />
903 - <?php
904 - } else {
905 - ?>
906 - &nbsp;&mdash;&nbsp;
907 - <?php
908 - }
909 - ?>
910 - </td>
911 - </tr>
912 - <?php
748 +/**
749 + * Register the widget.
750 + *
751 + * @return void
752 + */
753 +function mailchimp_sf_register_widgets() {
754 + if ( mailchimp_sf_get_api() ) {
755 + register_widget( 'Mailchimp_SF_Widget' );
913 756 }
914 - ?>
915 - </table>
916 - <?php
917 757 }
758 +add_action( 'widgets_init', 'mailchimp_sf_register_widgets' );
918 759
919 -?>
760 +/**
761 + * Add shortcode
762 + *
763 + * @return string
764 + */
765 +function mailchimp_sf_shortcode() {
766 + ob_start();
767 + mailchimp_sf_signup_form();
768 + return ob_get_clean();
769 +}
770 +add_shortcode( 'mailchimpsf_form', 'mailchimp_sf_shortcode' );
920 771
921 -<h4><?php esc_html_e('Interest Groups', 'mailchimp_i18n'); ?></h4>
772 +/**
773 + * Cleans up merge fields and interests to make them
774 + * API 3.0-friendly.
775 + *
776 + * @param [type] $merge Merge fields
777 + * @param [type] $igs Interest groups
778 + * @param string $email_type Email type
779 + * @param string $email Email
780 + * @param string|false $status Status The subscription status ('subscribed', 'unsubscribed', 'pending', etc.) or false if an error occurred.
781 + * @param string $double_optin Whether double opt-in is enabled. "1" for enabled and "" for disabled.
782 + * @return stdClass
783 + */
784 +function mailchimp_sf_subscribe_body( $merge, $igs, $email_type, $email, $status, $double_optin ) {
785 + $body = new stdClass();
786 + $body->email_address = $email;
787 + $body->email_type = $email_type;
788 + $body->merge_fields = $merge;
922 789
923 -<?php
924 -// Interest Groups Table
925 -$ig = get_option('mc_interest_groups');
790 + if ( ! empty( $igs ) ) {
791 + $body->interests = $igs;
792 + }
926 793
927 -if (!is_array($ig) || empty($ig) || $ig == 'N') {
928 - ?>
929 - <em><?php esc_html_e('No Interest Groups Setup for this List', 'mailchimp_i18n'); ?></em>
930 - <?php
931 -}
932 -else {
933 - ?>
934 - <table class='widefat'>
935 - <tr valign="top">
936 - <th width="75px">
937 - <label for="mc_show_interest_groups"><?php esc_html_e('Show?', 'mailchimp_i18n'); ?></label>
938 - </th>
939 - <th>
940 - <input name="mc_show_interest_groups" id="mc_show_interest_groups" type="checkbox" id="mc_show_interest_groups" class="code"<?php checked('on', get_option('mc_show_interest_groups')); ?> />
941 - </th>
942 - </tr>
943 - <tr valign="top">
944 - <th><?php esc_html_e('Name', 'mailchimp_i18n'); ?>:</th>
945 - <th><?php echo esc_html($ig['name']); ?></th>
946 - </tr>
947 - <tr valign="top">
948 - <th><?php esc_html_e('Input Type', 'mailchimp_i18n'); ?>:</th>
949 - <td><?php echo esc_html($ig['form_field']); ?></td>
950 - </tr>
951 - <tr valign="top">
952 - <th><?php esc_html_e('Options', 'mailchimp_i18n'); ?>:</th>
953 - <td>
954 - <ul>
955 - <?php
956 - foreach($ig['groups'] as $interest){
957 - ?>
958 - <li><?php echo esc_html($interest['name']); ?></li>
959 - <?php
960 - }
961 - ?>
962 - </ul>
963 - </td>
964 - </tr>
965 - </table>
966 -<?php
967 -}
968 -?>
969 -<p class="submit">
970 -<input type="submit" value="<?php esc_attr_e('Update Subscribe Form Settings', 'mailchimp_i18n'); ?>" class="button" />
971 -</p>
972 -</div>
973 -</form>
974 -</div>
975 -</div><!--wrap-->
976 -<?php
977 -}//mailchimpSF_setup_page()
794 + // Early return for already subscribed users
795 + if ( 'subscribed' === $status ) {
796 + return $body;
797 + }
978 798
799 + // Subscribe the email immediately unless double opt-in is enabled
800 + // "unsubscribed" and "subscribed" existing emails have been excluded at this stage
801 + // "pending" emails should follow double opt-in rules
802 + $body->status = $double_optin ? 'pending' : 'subscribed';
979 803
980 -function mailchimpSF_register_widgets() {
981 - register_widget('mailchimpSF_Widget');
804 + return $body;
982 805 }
983 -add_action('widgets_init', 'mailchimpSF_register_widgets');
984 806
985 -function mailchimpSF_shortcode($atts){
986 - ob_start();
987 - mailchimpSF_signup_form();
988 - return ob_get_clean();
807 +/**
808 + * Check the status of a subscriber in the list.
809 + *
810 + * @param string $endpoint API endpoint to check the status.
811 + * @return string|false The subscription status ('subscribed', 'unsubscribed', 'pending', etc.) or false if the API returned 404 or an error occurred.
812 + */
813 +function mailchimp_sf_check_status( $endpoint ) {
814 + $endpoint .= '?fields=status';
815 + $api = mailchimp_sf_get_api();
816 + $subscriber = $api->get( $endpoint, null );
817 + if ( is_wp_error( $subscriber ) ) {
818 + return false;
819 + }
820 + return $subscriber['status'];
989 821 }
990 -add_shortcode('mailchimpsf_form', 'mailchimpSF_shortcode');
991 822
992 823 /**
993 - * Attempts to signup a user, per the $_POST args.
994 - *
995 - * This sets a global message, that is then used in the widget
996 - * output to retrieve and display that message.
824 + * Verify key
997 825 *
998 - * @return bool
826 + * @param MailChimp_API $api API instance
827 + * @return mixed
999 828 */
1000 -function mailchimpSF_signup_submit() {
1001 - $mv = get_option('mc_merge_vars');
1002 - $ig = get_option('mc_interest_groups');
1003 -
1004 - $success = true;
1005 - $listId = get_option('mc_list_id');
1006 - $email = $_POST['mc_mv_EMAIL'];
1007 - $merge = $errs = array(); // Set up some vars
1008 -
1009 - // Loop through our Merge Vars, and if they're empty, but required, then print an error, and mark as failed
1010 - foreach($mv as $var) {
1011 - $opt = 'mc_mv_'.$var['tag'];
1012 - if ($var['req'] == 'Y' && trim($_POST[$opt]) == '') {
1013 - $success = false;
1014 - $errs[] = sprintf(__("You must fill in %s.", 'mailchimp_i18n'), esc_html($var['name']));
1015 - }
1016 - else {
1017 - if ($var['tag'] != 'EMAIL') {
1018 - $merge[$var['tag']] = $_POST[$opt];
1019 - }
1020 - }
829 +function mailchimp_sf_verify_key( $api ) {
830 + $user = $api->get( '' );
831 + if ( is_wp_error( $user ) ) {
832 + return $user;
1021 833 }
1022 -
1023 - // Head back to the beginning of the merge vars array
1024 - reset($mv);
1025 -
1026 -
1027 - if (get_option('mc_show_interest_groups')=='on') {
1028 - switch ($ig['form_field']) {
1029 - case 'select':
1030 - case 'dropdown':
1031 - case 'radio':
1032 - $merge['INTERESTS'] = str_replace(',', '\,', $_POST['interests']);
1033 - break;
1034 - case 'checkbox':
1035 - if (isset($_POST['interests'])) {
1036 - foreach ($_POST['interests'] as $i => $nothing) {
1037 - $merge['INTERESTS'] .= str_replace(',', '\,', $i).',';
1038 - }
1039 - }
1040 - break;
1041 - default:
1042 - // Nothing
1043 - break;
1044 - }
1045 - }
1046 -
1047 -
1048 - // If we're good
1049 - if ($success) {
1050 - // Clear out empty merge vars
1051 - foreach ($merge as $k => $v) {
1052 - if (trim($v) === '') {
1053 - unset($merge[$k]);
1054 - }
1055 - }
1056 -
1057 - // If we have an empty $merge, then assign empty string.
1058 - if (count($merge) == 0 || $merge == '') {
1059 - $merge = '';
1060 - }
1061 834
1062 - $api = new mailchimpSF_MCAPI(get_option('mc_apikey'));
1063 - $retval = $api->listSubscribe( $listId, $email, $merge);
1064 - if (!$retval) {
1065 - switch($api->errorCode) {
1066 - case '214' :
1067 - $errs[] = __("That email address is already subscribed to the list", 'mailchimp_i18n').'.';
1068 - break;
1069 - case '250' :
1070 - list($field, $rest) = explode(' ', $api->errorMessage, 2);
1071 - $errs[] = sprintf(__("You must fill in %s.", 'mailchimp_i18n'), esc_html($field));
1072 - break;
1073 - case '254' :
1074 - list($i1, $i2, $i3, $field, $rest) = explode(' ',$api->errorMessage,5);
1075 - $errs[] = sprintf(__("%s has invalid content.", 'mailchimp_i18n'), esc_html($field));
1076 - break;
1077 - case '270' :
1078 - $errs[] = __("An invalid Interest Group was selected", 'mailchimp_i18n').'.';
1079 - break;
1080 - case '502' :
1081 - $errs[] = __("That email address is invalid", 'mailchimp_i18n').'.';
1082 - break;
1083 - default:
1084 - $errs[] = $api->errorCode.":".$api->errorMessage;
1085 - break;
1086 - }
1087 - $success = false;
1088 - }
1089 - else {
1090 - $msg = "<strong class='mc_success_msg'>".esc_html(__("Success, you've been signed up! Please look for our confirmation email!", 'mailchimp_i18n'))."</strong>";
1091 - }
835 + // Might as well set this data if we have it already.
836 + $valid_roles = array( 'owner', 'admin', 'manager' );
837 + if ( isset( $user['role'] ) && in_array( $user['role'], $valid_roles, true ) ) {
838 + update_option( 'mc_api_key', $api->key );
839 + update_option( 'mc_user', $user );
840 + update_option( 'mc_datacenter', $api->datacenter );
841 +
842 + } else {
843 + $msg = esc_html__( 'API Key must belong to "Owner", "Admin", or "Manager."', 'mailchimp' );
844 + return new WP_Error( 'mc-invalid-role', $msg );
1092 845 }
1093 -
1094 - // If we have errors, then show them
1095 - if (count($errs) > 0) {
1096 - $msg = '<span class="mc_error_msg">';
1097 - foreach($errs as $error){
1098 - $msg .= '&raquo; '.esc_html($error).'<br />';
1099 - }
1100 - $msg .= '</span>';
1101 - }
1102 -
1103 - // Set our global message
1104 - mailchimpSF_global_msg($msg);
1105 -
1106 - return $success;
1107 846 }
1108 847
848 +/**
849 + * Update profile URL.
850 + *
851 + * @param string $email Email
852 + * @return string
853 + */
854 +function mailchimp_sf_update_profile_url( $email ) {
855 + $dc = get_option( 'mc_datacenter' );
856 + // This is the expected encoding for emails.
857 + $eid = base64_encode( $email ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode -- ignoring because this is the expected data for the endpoint
858 + $user = get_option( 'mc_user' );
859 + $list_id = get_option( 'mc_list_id' );
860 + $url = 'http://' . $dc . '.list-manage.com/subscribe/send-email?u=' . $user['account_id'] . '&id=' . $list_id . '&e=' . $eid;
861 + return $url;
862 +}
1109 863
864 +/**
865 + * Delete options
866 + *
867 + * @param array $options Options
868 + * @return void
869 + */
870 +function mailchimp_sf_delete_options( $options = array() ) {
871 + foreach ( $options as $option ) {
872 + delete_option( $option );
873 + }
874 +}
1110 875
1111 876 /**********************
1112 877 * Utility Functions *
1113 -**********************/
878 + **********************/
1114 879 /**
1115 880 * Utility function to allow placement of plugin in plugins, mu-plugins, child or parent theme's plugins folders
1116 - *
881 + *
1117 882 * This function must be ran _very early_ in the load process, as it sets up important constants for the rest of the plugin
1118 883 */
1119 -function mailchimpSF_where_am_i() {
884 +function mailchimp_sf_where_am_i() {
1120 885 $locations = array(
1121 - 'plugins' => array(
1122 - 'dir' => WP_PLUGIN_DIR,
1123 - 'url' => plugins_url()
886 + 'plugins' => array(
887 + 'dir' => plugin_dir_path( __FILE__ ),
888 + 'url' => plugins_url(),
1124 889 ),
1125 890 'mu_plugins' => array(
1126 - 'dir' => WPMU_PLUGIN_DIR,
891 + 'dir' => plugin_dir_path( __FILE__ ),
1127 892 'url' => plugins_url(),
1128 893 ),
1129 - 'template' => array(
1130 - 'dir' => trailingslashit(get_template_directory()).'plugins/',
1131 - 'url' => trailingslashit(get_template_directory_uri()).'plugins/',
894 + 'template' => array(
895 + 'dir' => trailingslashit( get_template_directory() ) . 'plugins/',
896 + 'url' => trailingslashit( get_template_directory_uri() ) . 'plugins/',
1132 897 ),
1133 898 'stylesheet' => array(
1134 - 'dir' => trailingslashit(get_stylesheet_directory()).'plugins/',
1135 - 'url' => trailingslashit(get_stylesheet_directory_uri()).'plugins/',
899 + 'dir' => trailingslashit( get_stylesheet_directory() ) . 'plugins/',
900 + 'url' => trailingslashit( get_stylesheet_directory_uri() ) . 'plugins/',
1136 901 ),
1137 902 );
1138 903
1139 904 // Set defaults
1140 - $mscf_dir = trailingslashit(WP_PLUGIN_DIR).'mailchimp/';
1141 - $mscf_url = trailingslashit(WP_PLUGIN_URL).'mailchimp/';
905 + $mscf_dirbase = trailingslashit( basename( __DIR__ ) ); // Typically wp-mailchimp/ or mailchimp/
906 + $mscf_dir = trailingslashit( plugin_dir_path( __FILE__ ) );
907 + $mscf_url = trailingslashit( plugins_url( '', __FILE__ ) );
1142 908
1143 909 // Try our hands at finding the real location
1144 - foreach ($locations as $key => $loc) {
1145 - $dir = trailingslashit($loc['dir']).'mailchimp/';
1146 - $url = trailingslashit($loc['url']).'mailchimp/';
1147 - if (is_file($dir.basename(__FILE__))) {
910 + foreach ( $locations as $key => $loc ) {
911 + $dir = trailingslashit( $loc['dir'] ) . $mscf_dirbase;
912 + $url = trailingslashit( $loc['url'] ) . $mscf_dirbase;
913 + if ( is_file( $dir . basename( __FILE__ ) ) ) {
1148 914 $mscf_dir = $dir;
1149 915 $mscf_url = $url;
1150 916 break;
1151 917 }
1152 918 }
919 +
1153 920 // Define our complete filesystem path
1154 - define('MCSF_DIR', $mscf_dir);
1155 -
1156 - /* Lang location needs to be relative *from* ABSPATH,
1157 - so strip it out of our language dir location */
1158 - define('MCSF_LANG_DIR', str_replace(ABSPATH, '', MCSF_DIR));
1159 -
921 + define( 'MCSF_DIR', $mscf_dir );
922 +
1160 923 // Define our complete URL to the plugin folder
1161 - define('MCSF_URL', $mscf_url);
924 + define( 'MCSF_URL', $mscf_url );
1162 925 }
1163 926
1164 927
1165 -?>
928 +/**
929 + * MODIFIED VERSION of wp_verify_nonce from WP Core. Core was not overridden to prevent problems when replacing
930 + * something universally.
931 + *
932 + * Verify that correct nonce was used with time limit.
933 + *
934 + * The user is given an amount of time to use the token, so therefore, since the
935 + * UID and $action remain the same, the independent variable is the time.
936 + *
937 + * @param string $nonce Nonce that was used in the form to verify
938 + * @param string|int $action Should give context to what is taking place and be the same when nonce was created.
939 + * @return bool Whether the nonce check passed or failed.
940 + */
941 +function mailchimp_sf_verify_nonce( $nonce, $action = -1 ) {
942 + $user = wp_get_current_user();
943 + $uid = (int) $user->ID;
944 + if ( ! $uid ) {
945 + $uid = apply_filters( 'nonce_user_logged_out', $uid, $action );
946 + }
947 +
948 + if ( empty( $nonce ) ) {
949 + return false;
950 + }
951 +
952 + $token = 'MAILCHIMP';
953 + $i = wp_nonce_tick();
954 +
955 + // Nonce generated 0-12 hours ago
956 + $expected = substr( wp_hash( $i . '|' . $action . '|' . $uid . '|' . $token, 'nonce' ), -12, 10 );
957 + if ( hash_equals( $expected, $nonce ) ) {
958 + return 1;
959 + }
960 +
961 + // Nonce generated 12-24 hours ago
962 + $expected = substr( wp_hash( ( $i - 1 ) . '|' . $action . '|' . $uid . '|' . $token, 'nonce' ), -12, 10 );
963 + if ( hash_equals( $expected, $nonce ) ) {
964 + return 2;
965 + }
966 +
967 + // Invalid nonce
968 + return false;
969 +}
970 +
971 +
972 +/**
973 + * MODIFIED VERSION of wp_create_nonce from WP Core. Core was not overridden to prevent problems when replacing
974 + * something universally.
975 + *
976 + * Creates a cryptographic token tied to a specific action, user, and window of time.
977 + *
978 + * @param string $action Scalar value to add context to the nonce.
979 + * @return string The token.
980 + */
981 +function mailchimp_sf_create_nonce( $action = -1 ) {
982 + $user = wp_get_current_user();
983 + $uid = (int) $user->ID;
984 + if ( ! $uid ) {
985 + /** This filter is documented in wp-includes/pluggable.php */
986 + $uid = apply_filters( 'nonce_user_logged_out', $uid, $action );
987 + }
988 +
989 + $token = 'MAILCHIMP';
990 + $i = wp_nonce_tick();
991 +
992 + return substr( wp_hash( $i . '|' . $action . '|' . $uid . '|' . $token, 'nonce' ), -12, 10 );
993 +}
994 +
995 +/**
996 + * Get Mailchimp Access Token.
997 + *
998 + * @since 1.6.0
999 + * @return string|bool
1000 + */
1001 +function mailchimp_sf_get_access_token() {
1002 + $access_token = get_option( 'mailchimp_sf_access_token' );
1003 + if ( empty( $access_token ) ) {
1004 + return false;
1005 + }
1006 +
1007 + $data_encryption = new Mailchimp_Data_Encryption();
1008 + $access_token = $data_encryption->decrypt( $access_token );
1009 +
1010 + // If decryption fails, display notice to user to re-authenticate.
1011 + if ( false === $access_token ) {
1012 + update_option( 'mailchimp_sf_auth_error', true );
1013 + }
1014 +
1015 + return $access_token;
1016 +}
1017 +
1018 +/**
1019 + * Should display Mailchimp Signup form.
1020 + *
1021 + * @since 1.6.0
1022 + * @return bool
1023 + */
1024 +function mailchimp_sf_should_display_form() {
1025 + return mailchimp_sf_get_api() && ! get_option( 'mailchimp_sf_auth_error' ) && get_option( 'mc_list_id' );
1026 +}
1027 +
1028 +/**
1029 + * Get Mailchimp Lists.
1030 + *
1031 + * @since 2.1.0
1032 + * @return array|WP_Error|false List of Mailchimp lists, or an error/false from the API request.
1033 + */
1034 +function mailchimp_sf_get_lists() {
1035 + /**
1036 + * Filter the limit of lists to fetch.
1037 + *
1038 + * This value is sanitized to a positive integer and clamped before the API request.
1039 + * Defaults to 100. 1000 is the maximum allowed by the API. 1 is the minimum allowed.
1040 + */
1041 + $limit = apply_filters( 'mailchimp_sf_list_limit', 100 ); // Default to 100.
1042 + $limit = max( 1, min( 1000, absint( $limit ) ) );
1043 +
1044 + $api = mailchimp_sf_get_api();
1045 + if ( ! $api ) {
1046 + return array();
1047 + }
1048 +
1049 + return $api->get( 'lists', $limit, array( 'fields' => 'lists.id,lists.name,lists.email_type_option' ) );
1050 +}