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 +826 -962 1.5.7trunk View file →
@@ -1,92 +1,179 @@
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.5.7
7 -Author: MailChimp
8 -Author URI: https://mailchimp.com/
9 -*/
10 -/* Copyright 2008-2012 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.5.7');
70 +define( 'MCSF_VER', '2.1.0' );
29 71
30 72 // What's our permission (capability) threshold
31 -define('MCSF_CAP_THRESHOLD', 'manage_options');
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('MailChimp_API')) {
38 - $path = plugin_dir_path(__FILE__);
39 - require_once($path . 'lib/mailchimp/mailchimp.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';
40 82 }
41 83
84 +// Encryption utility class.
85 +require_once plugin_dir_path( __FILE__ ) . 'includes/class-mailchimp-data-encryption.php';
86 +
42 87 // includes the widget code so it can be easily called either normally or via ajax
43 -include_once('mailchimp_widget.php');
88 +require_once 'mailchimp_widget.php';
44 89
45 90 // includes the backwards compatibility functions
46 -include_once('mailchimp_compat.php');
91 +require_once 'mailchimp_compat.php';
47 92
93 +// Upgrade routines.
94 +require_once 'mailchimp_upgrade.php';
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();
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();
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 +
48 140 /**
49 141 * Do the following plugin setup steps here
50 142 *
51 - * Internationalization
52 143 * Resource (JS & CSS) enqueuing
53 144 *
54 145 * @return void
55 146 */
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');
147 +function mailchimp_sf_plugin_init() {
61 148
62 - // Remove Sopresto check. If user does not have API key, make them authenticate.
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 + }
63 152
64 - if (get_option('mc_list_id') && get_option('mc_merge_field_migrate') != true && mailchimpSF_get_api() !== false) {
65 - mailchimpSF_update_merge_fields(get_option('mc_list_id'));
66 - }
67 -
68 - // Bring in our appropriate JS and CSS resources
69 - mailchimpSF_load_resources();
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 + }
70 157 }
71 158
72 -add_action( 'init', 'mailchimpSF_plugin_init' );
159 +add_action( 'init', 'mailchimp_sf_plugin_init' );
73 160
74 -
75 161 /**
76 - * Add the settings link to the MailChimp plugin row
162 + * Add the settings link to the Mailchimp plugin row
77 163 *
78 164 * @param array $links - Links for the plugin
79 165 * @return array - Links
80 166 */
81 -function mailchimpSD_plugin_action_links($links) {
82 - $settings_page = add_query_arg(array('page' => 'mailchimpSF_options'), admin_url('options-general.php'));
83 - $settings_link = '<a href="'.esc_url($settings_page).'">'.__('Settings', 'mailchimp_i18n' ).'</a>';
84 - array_unshift($links, $settings_link);
85 - return $links;
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;
86 172 }
87 -add_filter('plugin_action_links_'.plugin_basename(__FILE__), 'mailchimpSD_plugin_action_links', 10, 1);
88 173
174 +add_filter( 'plugin_action_links_' . plugin_basename( __FILE__ ), 'mailchimp_sf_plugin_action_links', 10, 1 );
175 +
89 176 /**
90 177 * Loads the appropriate JS and CSS resources depending on
91 178 * settings and context (admin or not)
92 179 *
@@ -91,249 +178,158 @@
91 178 * settings and context (admin or not)
92 179 *
93 180 * @return void
94 181 */
95 -function mailchimpSF_load_resources() {
96 - // JS
97 - if (get_option('mc_use_javascript') == 'on') {
98 - if (!is_admin()) {
99 - wp_enqueue_script('jquery_scrollto', MCSF_URL.'/js/scrollTo.js', array('jquery'), MCSF_VER);
100 - wp_enqueue_script('mailchimpSF_main_js', MCSF_URL.'/js/mailchimp.js', array('jquery', 'jquery-form'), MCSF_VER);
101 - // some javascript to get ajax version submitting to the proper location
102 - global $wp_scripts;
103 - $wp_scripts->localize('mailchimpSF_main_js', 'mailchimpSF', array(
104 - 'ajax_url' => trailingslashit(home_url()),
105 - ));
106 - }
107 - }
182 +function mailchimp_sf_load_resources() {
183 + // JS
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 + );
108 191
109 - if (get_option('mc_use_datepicker') == 'on' && !is_admin()) {
110 - // Datepicker theme
111 - wp_enqueue_style('flick', MCSF_URL.'/css/flick/flick.css'
112 - );
113 - // Datepicker JS
114 - wp_enqueue_script('datepicker', MCSF_URL.'/js/datepicker.js', array('jquery','jquery-ui-core'));
115 - }
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' );
195 + }
116 196
117 - if(get_option('mc_nuke_all_styles') != true) {
118 - wp_enqueue_style('mailchimpSF_main_css', home_url('?mcsf_action=main_css&ver='.MCSF_VER, 'relative'));
119 - wp_enqueue_style('mailchimpSF_ie_css', MCSF_URL.'css/ie.css');
120 - global $wp_styles;
121 - $wp_styles->add_data( 'mailchimpSF_ie_css', 'conditional', 'IE' );
122 - }
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 +
206 + // CSS
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 );
209 +
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 );
214 + }
215 + }
123 216 }
124 217
218 +/**
219 + * Custom styles CSS
220 + *
221 + * @return string
222 + */
223 +function mailchimp_sf_custom_style_css() {
224 + ob_start();
225 + ?>
226 + .mc_signup_form {
227 + padding:5px;
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' ) ); ?>;
233 + }
234 + <?php
235 + return ob_get_clean();
236 +}
125 237
126 238 /**
127 - * Loads resources for the MailChimp admin page
239 + * Request handler
128 240 *
129 241 * @return void
130 242 */
131 -function mc_admin_page_load_resources() {
132 - wp_enqueue_style('mailchimpSF_admin_css', MCSF_URL.'css/admin.css');
133 -}
134 -add_action('load-settings_page_mailchimpSF_options', 'mc_admin_page_load_resources');
243 +function mailchimp_sf_request_handler() {
244 + if ( isset( $_POST['mcsf_action'] ) ) {
245 + switch ( $_POST['mcsf_action'] ) {
246 + case 'logout':
247 + // Check capability & Verify nonce
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?' );
254 + }
135 255
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 );
259 + break;
260 + case 'change_form_settings':
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?' );
267 + }
136 268
137 -/**
138 - * Loads jQuery Datepicker for the date-pick class
139 - **/
140 -function mc_datepicker_load() {
141 - require_once(MCSF_DIR . '/views/datepicker.php');
269 + // Update the form settings
270 + mailchimp_sf_save_general_form_settings();
271 + break;
272 + }
273 + }
142 274 }
143 -if (get_option('mc_use_datepicker') == 'on' && !is_admin()) {
144 - add_action('wp_head', 'mc_datepicker_load');
145 -}
275 +add_action( 'init', 'mailchimp_sf_request_handler' );
146 276
147 277 /**
148 - * Handles requests that as light-weight a load as possible.
149 - * typically, JS or CSS
150 - **/
151 -function mailchimpSF_early_request_handler() {
152 - if (isset($_GET['mcsf_action'])) {
153 - switch ($_GET['mcsf_action']) {
154 - case 'main_css':
155 - header("Content-type: text/css");
156 - mailchimpSF_main_css();
157 - exit;
158 - }
159 - }
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 );
160 286 }
161 -add_action('init', 'mailchimpSF_early_request_handler', 0);
162 287
163 288 /**
164 - * Outputs the front-end CSS. This checks several options, so it
165 - * was best to put it in a Request-handled script, as opposed to
166 - * a static file.
289 + * Get auth key
290 + *
291 + * @param mixed $salt Salt
292 + * @return string
167 293 */
168 -function mailchimpSF_main_css() {
169 - require_once(MCSF_DIR . '/views/css/frontend.php');
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 );
170 299 }
171 300
172 -
173 301 /**
174 - * Add our settings page to the admin menu
302 + * Return auth nonce salt
175 303 *
176 - * @return void
304 + * @return string
177 305 */
178 -function mailchimpSF_add_pages(){
179 - // Add settings page for users who can edit plugins
180 - add_options_page( __( 'MailChimp Setup', 'mailchimp_i18n' ), __( 'MailChimp Setup', 'mailchimp_i18n' ), MCSF_CAP_THRESHOLD, 'mailchimpSF_options', 'mailchimpSF_setup_page');
306 +function mailchimp_sf_auth_nonce_salt() {
307 + return md5( microtime() . isset( $_SERVER['SERVER_ADDR'] ) ? sanitize_text_field( wp_unslash( $_SERVER['SERVER_ADDR'] ) ) : '' );
181 308 }
182 -add_action('admin_menu', 'mailchimpSF_add_pages');
183 309
184 -function mailchimpSF_request_handler() {
185 - if (isset($_POST['mcsf_action'])) {
186 - switch ($_POST['mcsf_action']) {
187 - case 'login':
188 - $key = trim($_POST['mailchimpSF_api_key']);
189 -
190 - try {
191 - $api = new MailChimp_API($key);
192 - } catch (Exception $e) {
193 - $msg = "<strong class='mc_error_msg'>" . $e->getMessage() . "</strong>";
194 - mailchimpSF_global_msg($msg);
195 - break;
196 - }
197 -
198 - $key = mailchimpSF_verify_key($api);
199 - if(is_wp_error($key)) {
200 - $msg = "<strong class='mc_error_msg'>" . $key->get_error_message() . "</strong>";
201 - mailchimpSF_global_msg($msg);
202 - }
203 -
204 - break;
205 - case 'logout':
206 - // Check capability & Verify nonce
207 - if (!current_user_can(MCSF_CAP_THRESHOLD) || !wp_verify_nonce($_POST['_mcsf_nonce_action'], 'mc_logout')) {
208 - wp_die('Cheatin&rsquo; huh?');
209 - }
210 -
211 - // erase auth information
212 - $options = array('mc_api_key', 'mc_sopresto_user', 'mc_sopresto_public_key', 'mc_sopresto_secret_key');
213 - mailchimpSF_delete_options($options);
214 - break;
215 - case 'change_form_settings':
216 - if (!current_user_can(MCSF_CAP_THRESHOLD) || !wp_verify_nonce($_POST['_mcsf_nonce_action'], 'update_general_form_settings')) {
217 - wp_die('Cheatin&rsquo; huh?');
218 - }
219 -
220 - // Update the form settings
221 - mailchimpSF_save_general_form_settings();
222 - break;
223 - case 'mc_submit_signup_form':
224 - // Validate nonce
225 - if (!wp_verify_nonce($_POST['_mc_submit_signup_form_nonce'], 'mc_submit_signup_form')) {
226 - wp_die('Cheatin&rsquo; huh?');
227 - }
228 -
229 - // Attempt the signup
230 - mailchimpSF_signup_submit();
231 -
232 - // Do a different action for html vs. js
233 - switch ($_POST['mc_submit_type']) {
234 - case 'html':
235 - /* This gets set elsewhere! */
236 - break;
237 - case 'js':
238 - if (!headers_sent()){ //just in case...
239 - header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT', true, 200);
240 - }
241 - echo mailchimpSF_global_msg(); // Don't esc_html this, b/c we've already escaped it
242 - exit;
243 - }
244 - }
245 - }
246 -}
247 -add_action('init', 'mailchimpSF_request_handler');
248 -
249 -function mailchimpSF_migrate_sopresto() {
250 - $sopresto = get_option('mc_sopresto_secret_key');
251 - if(!$sopresto) {
252 - return;
253 - }
254 -
255 - // Talk to Sopresto, make exchange, delete old sopresto things.
256 - $body = array(
257 - 'public_key' => get_option('mc_sopresto_public_key'),
258 - 'hash' => sha1(get_option('mc_sopresto_public_key').get_option('mc_sopresto_secret_key'))
259 - );
260 -
261 - $url = 'https://sopresto.socialize-this.com/mailchimp/exchange';
262 - $args = array(
263 - 'method' => 'POST',
264 - 'timeout' => 500,
265 - 'redirection' => 5,
266 - 'httpversion' => '1.0',
267 - 'user-agent' => 'MailChimp WordPress Plugin/' . get_bloginfo( 'url' ),
268 - 'body' => $body
269 - );
270 -
271 - //post to sopresto
272 - $key = wp_remote_post($url, $args);
273 - if(!is_wp_error($key) && $key['response']['code'] == 200) {
274 - $key = json_decode($key['body']);
275 - try {
276 - $api = new MailChimp_API($key->response);
277 - } catch (Exception $e) {
278 - $msg = "<strong class='mc_error_msg'>" . $e->getMessage() . "</strong>";
279 - mailchimpSF_global_msg($msg);
280 - return;
281 - }
282 -
283 - $verify = mailchimpSF_verify_key($api);
284 -
285 - //something went wrong with the key that we had
286 - if(is_wp_error($verify)) {
287 - return;
288 - }
289 -
290 - delete_option('mc_sopresto_public_key');
291 - delete_option('mc_sopresto_secret_key');
292 - delete_option('mc_sopresto_user');
293 -
294 - return;
295 - }
296 -
297 - // Nothing to do here.
298 - return;
299 -}
300 -
301 -function mailchimpSF_update_merge_fields($list_id)
302 -{
303 - mailchimpSF_get_merge_vars(get_option('mc_list_id'), true);
304 - mailchimpSF_get_interest_categories(get_option('mc_list_id'), true);
305 - update_option('mc_merge_field_migrate', true);
306 -}
307 -
308 -function mailchimpSF_auth_nonce_key($salt = null) {
309 - if (is_null($salt)) {
310 - $salt = mailchimpSF_auth_nonce_salt();
311 - }
312 - return 'social_authentication' . md5( AUTH_KEY . $salt );
313 -}
314 -
315 -function mailchimpSF_auth_nonce_salt() {
316 - return md5(microtime().$_SERVER['SERVER_ADDR']);
317 -}
318 -
319 310 /**
320 - * Creates new MailChimp API v3 object
311 + * Creates new Mailchimp API v3 object
321 312 *
322 313 * @return MailChimp_API | false
323 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 + }
324 322
325 -function mailchimpSF_get_api($force = false) {
326 - $key = get_option('mc_api_key');
327 - if($key) {
328 - return new MailChimp_API($key);
329 - }
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 );
327 + }
330 328
331 - return false;
329 + return false;
332 330 }
333 331
334 -
335 -
336 332 /**
337 333 * Checks to see if we're storing a password, if so, we need
338 334 * to upgrade to the API key
339 335 *
@@ -338,92 +334,117 @@
338 334 * to upgrade to the API key
339 335 *
340 336 * @return bool
341 337 **/
342 -function mailchimpSF_needs_upgrade() {
343 - $igs = get_option('mc_interest_groups');
338 +function mailchimp_sf_needs_upgrade() {
339 + $igs = get_option( 'mc_interest_groups' );
344 340
345 - if ($igs !== false // we have an option
346 - && (
347 - empty($igs) || // it can be an empty array (no interest groups)
348 - (is_array($igs) && isset($igs[0]['id'])) // OR it should be a populated array that's well-formed
349 - )) {
350 - return false; // no need to upgrade
351 - }
352 - else {
353 - return true; // yeah, let's do it
354 - }
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 + }
355 351 }
356 352
357 353 /**
358 - * Deletes all mailchimp options
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
359 358 **/
360 -function mailchimpSF_delete_setup() {
361 - $options = array('mc_user_id', 'mc_sopresto_user', 'mc_sopresto_public_key', 'mc_sopresto_secret_key', 'mc_rewards', 'mc_use_javascript', 'mc_use_datepicker', 'mc_use_unsub_link', 'mc_list_id', 'mc_list_name', 'mc_interest_groups', 'mc_merge_vars');
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 + );
362 368
363 - $igs = get_option('mc_interest_groups');
364 - if (is_array($igs)) {
365 - foreach ($igs as $ig) {
366 - $opt = 'mc_show_interest_groups_'.$ig['id'];
367 - $options[] = $opt;
368 - }
369 - }
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 - $mv = get_option('mc_merge_vars');
372 - if (is_array($mv)){
373 - foreach($mv as $var){
374 - $opt = 'mc_mv_'.$var['tag'];
375 - $options[] = $opt;
376 - }
377 - }
378 -
379 - mailchimpSF_delete_options($options);
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 + }
384 +
385 + mailchimp_sf_delete_options( $options );
380 386 }
381 387
382 388 /**
383 - * 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
384 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
385 397 * @return string/bool depending on get/set
386 - **/
387 -function mailchimpSF_global_msg($msg = null) {
388 - global $mcsf_msgs;
398 + */
399 +function mailchimp_sf_frontend_msg( $msg = null ) {
400 + global $mcsf_msgs;
389 401
390 - // Make sure we're formed properly
391 - if (!is_array($mcsf_msgs)) {
392 - $mcsf_msgs = array();
393 - }
402 + // Make sure we're formed properly
403 + if ( ! is_array( $mcsf_msgs ) ) {
404 + $mcsf_msgs = array();
405 + }
394 406
395 - // See if we're getting
396 - if (is_null($msg)) {
397 - return implode('', $mcsf_msgs);
398 - }
407 + // See if we're getting
408 + if ( is_null( $msg ) ) {
409 + return implode( '', $mcsf_msgs );
410 + }
399 411
400 - // Must be setting
401 - $mcsf_msgs[] = $msg;
402 - return true;
412 + // Must be setting
413 + $mcsf_msgs[] = $msg;
414 + return true;
403 415 }
404 416
405 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 +/**
406 430 * Sets the default options for the option form
407 - **/
408 -function mailchimpSF_set_form_defaults($list_name = '') {
409 - update_option('mc_header_content',__( 'Sign up for', 'mailchimp_i18n' ).' '.$list_name);
410 - update_option('mc_submit_text',__( 'Subscribe', 'mailchimp_i18n' ));
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' ) );
411 438
412 - update_option('mc_use_datepicker', 'on');
413 - update_option('mc_custom_style','off');
414 - update_option('mc_use_javascript','on');
415 - update_option('mc_double_optin', true);
416 - update_option('mc_use_unsub_link','off');
417 - update_option('mc_header_border_width','1');
418 - update_option('mc_header_border_color','E3E3E3');
419 - update_option('mc_header_background','FFFFFF');
420 - update_option('mc_header_text_color','CC6600');
439 + update_option( 'mc_custom_style', 'off' );
440 + update_option( 'mc_double_optin', true );
441 + update_option( 'mc_use_unsub_link', 'off' );
421 442
422 - update_option('mc_form_border_width','1');
423 - update_option('mc_form_border_color','E0E0E0');
424 - update_option('mc_form_background','FFFFFF');
425 - update_option('mc_form_text_color','3F3F3f');
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' );
426 447 }
427 448
428 449 /**
429 450 * Saves the General Form settings on the options page
@@ -429,698 +450,484 @@
429 450 * Saves the General Form settings on the options page
430 451 *
431 452 * @return void
432 453 **/
433 -function mailchimpSF_save_general_form_settings() {
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 );
465 + }
434 466
435 - // IF NOT DEV MODE
436 - if (isset($_POST['mc_rewards'])){
437 - update_option('mc_rewards', 'on');
438 - $msg = '<p class="success_msg">'.__('Monkey Rewards turned On!', 'mailchimp_i18n').'</p>';
439 - mailchimpSF_global_msg($msg);
440 - } else if (get_option('mc_rewards')!='off') {
441 - update_option('mc_rewards', 'off');
442 - $msg = '<p class="success_msg">'.__('Monkey Rewards turned Off!', 'mailchimp_i18n').'</p>';
443 - mailchimpSF_global_msg($msg);
444 - }
445 - if (isset($_POST['mc_use_javascript'])){
446 - update_option('mc_use_javascript', 'on');
447 - $msg = '<p class="success_msg">'.__('Fancy Javascript submission turned On!', 'mailchimp_i18n').'</p>';
448 - mailchimpSF_global_msg($msg);
449 - } else if (get_option('mc_use_javascript')!='off') {
450 - update_option('mc_use_javascript', 'off');
451 - $msg = '<p class="success_msg">'.__('Fancy Javascript submission turned Off!', 'mailchimp_i18n').'</p>';
452 - mailchimpSF_global_msg($msg);
453 - }
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 );
476 + }
454 477
455 - if (isset($_POST['mc_use_datepicker'])){
456 - update_option('mc_use_datepicker', 'on');
457 - $msg = '<p class="success_msg">'.__('Datepicker turned On!', 'mailchimp_i18n').'</p>';
458 - mailchimpSF_global_msg($msg);
459 - } else if (get_option('mc_use_datepicker')!='off') {
460 - update_option('mc_use_datepicker', 'off');
461 - $msg = '<p class="success_msg">'.__('Datepicker turned Off!', 'mailchimp_i18n').'</p>';
462 - mailchimpSF_global_msg($msg);
463 - }
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 );
487 + }
464 488
465 - /*Enable double optin toggle*/
466 -
467 - if(isset($_POST['mc_double_optin'])) {
468 - update_option('mc_double_optin', true);
469 - $msg = '<p class="success_msg">'.__('Double opt-in turned On!', 'mailchimp_i18n').'</p>';
470 - mailchimpSF_global_msg($msg);
471 - } else if (get_option('mc_double_optin') != false) {
472 - update_option('mc_double_optin', false);
473 - $msg = '<p class="success_msg">'.__('Double opt-in turned Off!', 'mailchimp_i18n').'</p>';
474 - mailchimpSF_global_msg($msg);
475 - }
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 + }
476 498
477 - /* NUKE the CSS! */
478 - if(isset($_POST['mc_nuke_all_styles'])) {
479 - update_option('mc_nuke_all_styles', true);
480 - $msg = '<p class="success_msg">'.__('MailChimp CSS turned Off!', 'mailchimp_i18n').'</p>';
481 - mailchimpSF_global_msg($msg);
482 - }elseif (get_option('mc_nuke_all_styles') !== false) {
483 - update_option('mc_nuke_all_styles', false);
484 - $msg = '<p class="success_msg">'.__('MailChimp CSS turned On!', 'mailchimp_i18n').'</p>';
485 - mailchimpSF_global_msg($msg);
486 - }
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 );
487 502
488 - /* Update existing */
489 - if (isset($_POST['mc_update_existing'])) {
490 - update_option('mc_update_existing', true);
491 - $msg = '<p class="success_msg">' . __('Update existing subscribers turned On!') . '</p>';
492 - mailchimpSF_global_msg($msg);
493 - } elseif (get_option('mc_update_existing') ==! false) {
494 - update_option('mc_update_existing', false);
495 - $msg = '<p class="success_msg">' . __('Update existing subscribers turned Off!') . '</p>';
496 - mailchimpSF_global_msg($msg);
497 - }
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 );
498 506
499 - if (isset($_POST['mc_use_unsub_link'])){
500 - update_option('mc_use_unsub_link', 'on');
501 - $msg = '<p class="success_msg">'.__('Unsubscribe link turned On!', 'mailchimp_i18n').'</p>';
502 - mailchimpSF_global_msg($msg);
503 - }
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 );
504 510
505 - elseif (get_option('mc_use_unsub_link')!='off') {
506 - update_option('mc_use_unsub_link', 'off');
507 - $msg = '<p class="success_msg">'.__('Unsubscribe link turned Off!', 'mailchimp_i18n').'</p>';
508 - mailchimpSF_global_msg($msg);
509 - }
511 + // Set Custom Style option
512 + update_option( 'mc_custom_style', isset( $_POST['mc_custom_style'] ) ? 'on' : 'off' );
510 513
511 - $content = stripslashes($_POST['mc_header_content']);
512 - $content = str_replace("\r\n","<br/>", $content);
513 - update_option('mc_header_content', $content );
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 + }
514 527
515 - $content = stripslashes($_POST['mc_subheader_content']);
516 - $content = str_replace("\r\n","<br/>", $content);
517 - update_option('mc_subheader_content', $content );
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 + }
518 540
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' );
547 + } else {
548 + update_option( $opt, 'off' );
549 + }
550 + }
551 + }
519 552
520 - $submit_text = stripslashes($_POST['mc_submit_text']);
521 - $submit_text = str_replace("\r\n","", $submit_text);
522 - update_option('mc_submit_text', $submit_text);
523 -
524 - // Set Custom Style option
525 - update_option('mc_custom_style', isset($_POST['mc_custom_style']) ? 'on' : 'off');
526 -
527 - //we told them not to put these things we are replacing in, but let's just make sure they are listening...
528 - if(isset($_POST['mc_form_border_width'])) {
529 - update_option('mc_form_border_width',str_replace('px', '', $_POST['mc_form_border_width']) );
530 - }
531 - if(isset($_POST['mc_form_border_color'])) {
532 - update_option('mc_form_border_color', str_replace('#', '', $_POST['mc_form_border_color']));
533 - }
534 - if(isset($_POST['mc_form_background'])){
535 - update_option('mc_form_background',str_replace('#', '', $_POST['mc_form_background']));
536 - }
537 - if(isset($_POST['mc_form_text_color'])) {
538 - update_option('mc_form_text_color', str_replace('#', '', $_POST['mc_form_text_color']));
539 - }
540 -
541 -
542 - // IF NOT DEV MODE
543 - $igs = get_option('mc_interest_groups');
544 - if (is_array($igs)) {
545 - foreach($igs as $var){
546 - $opt = 'mc_show_interest_groups_'.$var['id'];
547 - if (isset($_POST[$opt])){
548 - update_option($opt,'on');
549 - } else {
550 - update_option($opt,'off');
551 - }
552 - }
553 - }
554 -
555 - $mv = get_option('mc_merge_vars');
556 - if (is_array($mv)) {
557 - foreach($mv as $var){
558 - $opt = 'mc_mv_'.$var['tag'];
559 - if (isset($_POST[$opt]) || $var['required']=='Y'){
560 - update_option($opt,'on');
561 - } else {
562 - update_option($opt,'off');
563 - }
564 - }
565 - }
566 -
567 - $msg = '<p class="success_msg">'.esc_html(__('Successfully Updated your List Subscribe Form Settings!', 'mailchimp_i18n')).'</p>';
568 - mailchimpSF_global_msg($msg);
553 + $msg = esc_html__( 'Successfully Updated your List Subscribe Form Settings!', 'mailchimp' );
554 + admin_notice_success( $msg );
555 + // phpcs:enable WordPress.Security.NonceVerification.Missing
569 556 }
570 557
571 558 /**
572 559 * Sees if the user changed the list, and updates options accordingly
573 560 **/
574 -function mailchimpSF_change_list_if_necessary() {
575 - // Simple permission check before going through all this
576 - if (!current_user_can(MCSF_CAP_THRESHOLD)) { return; }
561 +function mailchimp_sf_change_list_if_necessary() {
562 + if ( ! isset( $_POST['mc_list_id'] ) ) {
563 + return;
564 + }
577 565
578 - $api = mailchimpSF_get_api();
579 - if (!$api) { return; }
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.' );
572 + }
580 573
581 - //we *could* support paging, but few users have that many lists (and shouldn't)
582 - $lists = $api->get('lists',100, array('fields' => 'lists.id,lists.name,lists.email_type_option'));
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 + }
583 579
584 - $lists = $lists['lists'];
580 + $lists = mailchimp_sf_get_lists();
581 + if ( is_wp_error( $lists ) || ! isset( $lists['lists'] ) ) {
582 + return;
583 + }
585 584
586 - if (is_array($lists) && !empty($lists) && isset($_POST['mc_list_id'])) {
585 + $lists = $lists['lists'];
587 586
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 - }
587 + if ( is_array( $lists ) && ! empty( $lists ) ) {
597 588
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']);
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 + }
603 599
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 + }
604 609
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
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'] );
614 615
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);
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 );
618 621
619 - $igs_text = ' ';
620 - if (is_array($igs)) {
621 - $igs_text .= sprintf(__('and %s Sets of Interest Groups', 'mailchimp_i18n'), count($igs));
622 - }
622 + $new_list = true;
623 + }
623 624
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 -}
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 );
635 628
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 - }
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 + }
644 634
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 -}
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' );
656 642
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 -}
643 + admin_notice_success( $msg );
644 + }
671 645
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'];
646 + // Update the lists option.
647 + update_option( 'mailchimp_sf_lists', $lists );
648 + }
697 649 }
698 650
699 -
700 651 /**
701 - * Outputs the Settings/Options page
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
702 658 */
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()
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 );
708 662
663 + // if we get an error back from the api, exit this process.
664 + if ( is_wp_error( $mv ) ) {
665 + return;
666 + }
709 667
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');
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 + }
716 672
717 -function mailchimpSF_shortcode($atts){
718 - ob_start();
719 - mailchimpSF_signup_form();
720 - return ob_get_clean();
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 + }
684 + }
685 + }
686 + return $mv['merge_fields'];
721 687 }
722 -add_shortcode('mailchimpsf_form', 'mailchimpSF_shortcode');
723 688
724 689 /**
725 - * Attempts to signup a user, per the $_POST args.
690 + * Add email field
726 691 *
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
692 + * @param array $merge Merge
693 + * @return array
731 694 */
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;
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;
809 707 }
810 708
811 - /*
812 - Cleans up merge fields and interests to make them
813 - API 3.0-friendly.
814 - */
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 );
815 720
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 - }
721 + // if we get an error back from the api, exis
722 + if ( is_wp_error( $igs ) ) {
723 + return;
724 + }
825 725
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 -}
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'];
837 732
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 - }
733 + // turn them all on by default
734 + if ( $new_list ) {
735 + update_option( $opt, 'on' );
736 + }
737 + ++$key;
738 + }
739 + }
847 740
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]) : '';
741 + if ( $update_option ) {
742 + update_option( 'mc_interest_groups', $igs['categories'] );
743 + }
859 744
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;
745 + return $igs['categories'];
901 746 }
902 747
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;
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' );
756 + }
924 757 }
758 +add_action( 'widgets_init', 'mailchimp_sf_register_widgets' );
925 759
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 -
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();
948 769 }
770 +add_shortcode( 'mailchimpsf_form', 'mailchimp_sf_shortcode' );
949 771
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 - }
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;
959 789
960 - // If we have an empty $merge, then assign empty string.
961 - if (count($merge) == 0 || $merge == '') {
962 - $merge = '';
963 - }
790 + if ( ! empty( $igs ) ) {
791 + $body->interests = $igs;
792 + }
964 793
965 - return $merge;
966 -}
794 + // Early return for already subscribed users
795 + if ( 'subscribed' === $status ) {
796 + return $body;
797 + }
967 798
968 -function mailchimpSF_groups_submit($igs) {
969 - $groups = mailchimpSF_set_all_groups_to_false();
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';
970 803
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;
804 + return $body;
1004 805 }
1005 806
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;
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'];
1019 821 }
1020 822
1021 -function mailchimpSF_verify_key($api) {
1022 - $user = $api->get('');
1023 - if (is_wp_error($user)) {
1024 - return $user;
1025 - }
823 +/**
824 + * Verify key
825 + *
826 + * @param MailChimp_API $api API instance
827 + * @return mixed
828 + */
829 +function mailchimp_sf_verify_key( $api ) {
830 + $user = $api->get( '' );
831 + if ( is_wp_error( $user ) ) {
832 + return $user;
833 + }
1026 834
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);
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 );
1033 841
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;
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 );
845 + }
1039 846 }
1040 847
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;
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;
1048 862 }
1049 863
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;
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 + }
1056 874 }
1057 875
1058 -function mailchimpSF_delete_options($options = array()) {
1059 - foreach($options as $option) {
1060 - delete_option($option);
1061 - }
1062 -}
1063 -
1064 -
1065 876 /**********************
1066 877 * Utility Functions *
1067 -**********************/
878 + **********************/
1068 879 /**
1069 880 * Utility function to allow placement of plugin in plugins, mu-plugins, child or parent theme's plugins folders
1070 881 *
1071 882 * This function must be ran _very early_ in the load process, as it sets up important constants for the rest of the plugin
1072 883 */
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 - );
884 +function mailchimp_sf_where_am_i() {
885 + $locations = array(
886 + 'plugins' => array(
887 + 'dir' => plugin_dir_path( __FILE__ ),
888 + 'url' => plugins_url(),
889 + ),
890 + 'mu_plugins' => array(
891 + 'dir' => plugin_dir_path( __FILE__ ),
892 + 'url' => plugins_url(),
893 + ),
894 + 'template' => array(
895 + 'dir' => trailingslashit( get_template_directory() ) . 'plugins/',
896 + 'url' => trailingslashit( get_template_directory_uri() ) . 'plugins/',
897 + ),
898 + 'stylesheet' => array(
899 + 'dir' => trailingslashit( get_stylesheet_directory() ) . 'plugins/',
900 + 'url' => trailingslashit( get_stylesheet_directory_uri() ) . 'plugins/',
901 + ),
902 + );
1092 903
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__));
904 + // Set defaults
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__ ) );
1097 908
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 - }
909 + // Try our hands at finding the real location
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__ ) ) ) {
914 + $mscf_dir = $dir;
915 + $mscf_url = $url;
916 + break;
917 + }
918 + }
1108 919
1109 - // Define our complete filesystem path
1110 - define('MCSF_DIR', $mscf_dir);
920 + // Define our complete filesystem path
921 + define( 'MCSF_DIR', $mscf_dir );
1111 922
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);
923 + // Define our complete URL to the plugin folder
924 + define( 'MCSF_URL', $mscf_url );
1118 925 }
1119 926
1120 927
1121 928 /**
1122 - * MODIFIED VERSION of wp_verify_nonce from WP Core. Core was not overridden to prevent problems when replacing
929 + * MODIFIED VERSION of wp_verify_nonce from WP Core. Core was not overridden to prevent problems when replacing
1123 930 * something universally.
1124 931 *
1125 932 * Verify that correct nonce was used with time limit.
1126 933 *
@@ -1126,45 +933,45 @@
1126 933 *
1127 934 * The user is given an amount of time to use the token, so therefore, since the
1128 935 * UID and $action remain the same, the independent variable is the time.
1129 936 *
1130 - * @param string $nonce Nonce that was used in the form to verify
937 + * @param string $nonce Nonce that was used in the form to verify
1131 938 * @param string|int $action Should give context to what is taking place and be the same when nonce was created.
1132 939 * @return bool Whether the nonce check passed or failed.
1133 940 */
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 - }
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 + }
1140 947
1141 - if ( empty( $nonce ) ) {
1142 - return false;
1143 - }
948 + if ( empty( $nonce ) ) {
949 + return false;
950 + }
1144 951
1145 - $token = 'MAILCHIMP';
1146 - $i = wp_nonce_tick();
952 + $token = 'MAILCHIMP';
953 + $i = wp_nonce_tick();
1147 954
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 - }
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 + }
1153 960
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 - }
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 + }
1159 966
1160 - // Invalid nonce
1161 - return false;
967 + // Invalid nonce
968 + return false;
1162 969 }
1163 970
1164 971
1165 972 /**
1166 - * MODIFIED VERSION of wp_create_nonce from WP Core. Core was not overridden to prevent problems when replacing
973 + * MODIFIED VERSION of wp_create_nonce from WP Core. Core was not overridden to prevent problems when replacing
1167 974 * something universally.
1168 975 *
1169 976 * Creates a cryptographic token tied to a specific action, user, and window of time.
1170 977 *
@@ -1170,17 +977,74 @@
1170 977 *
1171 978 * @param string $action Scalar value to add context to the nonce.
1172 979 * @return string The token.
1173 980 */
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 - }
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 + }
1181 988
1182 - $token = 'MAILCHIMP';
1183 - $i = wp_nonce_tick();
989 + $token = 'MAILCHIMP';
990 + $i = wp_nonce_tick();
1184 991
1185 - return substr( wp_hash( $i . '|' . $action . '|' . $uid . '|' . $token, 'nonce' ), -12, 10 );
1186 -}
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 +}