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 +257 -614 1.6.0trunk View file →
@@ -3,11 +3,11 @@
3 3 * Plugin Name: Mailchimp
4 4 * Plugin URI: https://mailchimp.com/help/connect-or-disconnect-list-subscribe-for-wordpress/
5 5 * Description: Add a Mailchimp signup form block, widget or shortcode to your WordPress site.
6 6 * Text Domain: mailchimp
7 - * Version: 1.6.0
8 - * Requires at least: 6.1
9 - * Requires PHP: 7.0
7 + * Version: 2.1.0
8 + * Requires at least: 6.6
9 + * Requires PHP: 7.4
10 10 * PHP tested up to: 8.3
11 11 * Author: Mailchimp
12 12 * Author URI: https://mailchimp.com/
13 13 * License: GPL-2.0-or-later
@@ -33,10 +33,42 @@
33 33 * along with this program; if not, write to the Free Software
34 34 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
35 35 */
36 36
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 + );
62 +
63 + // Exit early.
64 + return;
65 +}
66 +
67 +use function Mailchimp\WordPress\Includes\Admin\{admin_notice_error, admin_notice_success};
68 +
37 69 // Version constant for easy CSS refreshes
38 -define( 'MCSF_VER', '1.6.0' );
70 +define( 'MCSF_VER', '2.1.0' );
39 71
40 72 // What's our permission (capability) threshold
41 73 define( 'MCSF_CAP_THRESHOLD', 'manage_options' );
42 74
@@ -61,12 +93,51 @@
61 93 // Upgrade routines.
62 94 require_once 'mailchimp_upgrade.php';
63 95
64 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';
65 100 require_once plugin_dir_path( __FILE__ ) . 'includes/class-mailchimp-admin.php';
66 101 $admin = new Mailchimp_Admin();
67 102 $admin->init();
68 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 +
69 140 /**
70 141 * Do the following plugin setup steps here
71 142 *
72 143 * Resource (JS & CSS) enqueuing
@@ -74,16 +145,16 @@
74 145 * @return void
75 146 */
76 147 function mailchimp_sf_plugin_init() {
77 148
78 - // Remove Sopresto check. If user does not have API key, make them authenticate.
79 -
80 149 if ( get_option( 'mc_list_id' ) && get_option( 'mc_merge_field_migrate' ) !== '1' && mailchimp_sf_get_api() !== false ) {
81 150 mailchimp_sf_update_merge_fields();
82 151 }
83 152
84 - // Bring in our appropriate JS and CSS resources
85 - mailchimp_sf_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 + }
86 157 }
87 158
88 159 add_action( 'init', 'mailchimp_sf_plugin_init' );
89 160
@@ -109,95 +180,61 @@
109 180 * @return void
110 181 */
111 182 function mailchimp_sf_load_resources() {
112 183 // JS
113 - if ( get_option( 'mc_use_javascript' ) === 'on' ) {
114 - if ( ! is_admin() ) {
115 - wp_enqueue_script( 'mailchimp_sf_main_js', MCSF_URL . 'assets/js/mailchimp.js', array( 'jquery', 'jquery-form' ), MCSF_VER, true );
116 - // some javascript to get ajax version submitting to the proper location
117 - global $wp_scripts;
118 - $wp_scripts->localize(
119 - 'mailchimp_sf_main_js',
120 - 'mailchimpSF',
121 - array(
122 - 'ajax_url' => trailingslashit( home_url() ),
123 - )
124 - );
125 - }
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' );
126 195 }
127 196
128 - if ( get_option( 'mc_use_datepicker' ) === 'on' && ! is_admin() ) {
129 - // Datepicker theme
130 - wp_enqueue_style( 'flick', MCSF_URL . 'assets/css/flick/flick.css', array(), MCSF_VER );
197 + $wp_scripts->localize(
198 + 'mailchimp_sf_main_js',
199 + 'mailchimpSF',
200 + $localize_data
201 + );
131 202
132 - // Datepicker JS
133 - wp_enqueue_script( 'jquery-ui-datepicker' );
134 - }
203 + // Datepicker theme
204 + wp_enqueue_style( 'flick', MCSF_URL . 'assets/css/flick/flick.css', array(), MCSF_VER );
135 205
206 + // CSS
136 207 if ( get_option( 'mc_nuke_all_styles' ) !== '1' ) {
137 - wp_enqueue_style( 'mailchimp_sf_main_css', home_url( '?mcsf_action=main_css&ver=' . MCSF_VER, 'relative' ), array(), MCSF_VER );
138 - global $wp_styles;
139 - $wp_styles->add_data( 'mailchimp_sf_ie_css', 'conditional', 'IE' );
140 - }
141 -}
208 + wp_enqueue_style( 'mailchimp_sf_main_css', MCSF_URL . 'assets/css/frontend.css', array(), MCSF_VER );
142 209
143 -/**
144 - * Loads jQuery Datepicker for the date-pick class
145 - **/
146 -function mc_datepicker_load() {
147 - require_once MCSF_DIR . '/views/datepicker.php';
148 -}
149 -
150 -if ( get_option( 'mc_use_datepicker' ) === 'on' && ! is_admin() ) {
151 - add_action( 'wp_head', 'mc_datepicker_load' );
152 -}
153 -
154 -/**
155 - * Handles requests that as light-weight a load as possible.
156 - * typically, JS or CSS
157 - *
158 - * @return void
159 - */
160 -function mailchimp_sf_early_request_handler() {
161 - if ( isset( $_GET['mcsf_action'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- ignoring because this is only adding CSS
162 - switch ( $_GET['mcsf_action'] ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- ignoring because this is only adding CSS
163 - case 'main_css':
164 - header( 'Content-type: text/css' );
165 - mailchimp_sf_main_css();
166 - 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 );
167 214 }
168 215 }
169 216 }
170 217
171 -add_action( 'init', 'mailchimp_sf_early_request_handler', 0 );
172 -
173 218 /**
174 - * Outputs the front-end CSS. This checks several options, so it
175 - * was best to put it in a Request-handled script, as opposed to
176 - * a static file.
177 - */
178 -function mailchimp_sf_main_css() {
179 - require_once MCSF_DIR . '/views/css/frontend.php';
180 -}
181 -
182 -
183 -/**
184 - * Add our settings page to the admin menu
219 + * Custom styles CSS
185 220 *
186 - * @return void
221 + * @return string
187 222 */
188 -function mailchimp_sf_add_pages() {
189 - // Add settings page for users who can edit plugins
190 - add_menu_page(
191 - esc_html__( 'Mailchimp Setup', 'mailchimp' ),
192 - esc_html__( 'Mailchimp', 'mailchimp' ),
193 - MCSF_CAP_THRESHOLD,
194 - 'mailchimp_sf_options',
195 - 'mailchimp_sf_setup_page',
196 - 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIiBmaWxsPSJub25lIiB2aWV3Qm94PSIwIDAgMTAwIDEwMCI+PGcgZmlsbD0iI2E3YWFhZCIgY2xpcC1wYXRoPSJ1cmwoI2EpIj48cGF0aCBkPSJNNzEuOTcyIDQ3LjQ0OWMuOTk0IDAgMS44LTEuNTE2IDEuOC0zLjM4NSAwLTEuODY5LS44MDYtMy4zODQtMS44LTMuMzg0cy0xLjggMS41MTUtMS44IDMuMzg0YzAgMS44Ny44MDYgMy4zODUgMS44IDMuMzg1Wk01Ny43OTEgNDkuNjQ3YzIuNjg0IDAgNC44NTktLjcxMyA0Ljg1OS0xLjU5MiAwLS44OC0yLjE3NS0xLjU5My00Ljg1OC0xLjU5My0yLjY4NCAwLTQuODU5LjcxMy00Ljg1OSAxLjU5M3MyLjE3NSAxLjU5MiA0Ljg1OCAxLjU5MlpNNTkuMjg4IDUyLjI1NmMxLjYzIDAgMi45NTItLjQ3NSAyLjk1Mi0xLjA2MiAwLS41ODYtMS4zMjItMS4wNjEtMi45NTMtMS4wNjEtMS42MyAwLTIuOTUyLjQ3NS0yLjk1MiAxLjA2MSAwIC41ODcgMS4zMjIgMS4wNjIgMi45NTMgMS4wNjJaTTY4LjUyIDU0LjE0Yy44NCAwIDEuNTItLjU2MyAxLjUyLTEuMjU4IDAtLjY5NC0uNjgtMS4yNTctMS41Mi0xLjI1Ny0uODM4IDAtMS41MTguNTYzLTEuNTE4IDEuMjU3IDAgLjY5NS42OCAxLjI1NyAxLjUxOSAxLjI1N1pNNzMuMDU4IDUyLjY3NWMuNjQxIDAgMS4xNjEtLjcxMyAxLjE2MS0xLjU5M3MtLjUyLTEuNTkzLTEuMTYxLTEuNTkzYy0uNjQyIDAtMS4xNjIuNzEzLTEuMTYyIDEuNTkzcy41MiAxLjU5MyAxLjE2MiAxLjU5M1pNMjQuOTIyIDY2Ljc3NmMyLjg1NiAwIDUuMTcxLTIuNTk1IDUuMTcxLTUuNzk3IDAtMy4yMDEtMi4zMTUtNS43OTctNS4xNy01Ljc5Ny0yLjg1NyAwLTUuMTcyIDIuNTk2LTUuMTcyIDUuNzk3IDAgMy4yMDIgMi4zMTUgNS43OTcgNS4xNzEgNS43OTdaIi8+PHBhdGggZD0iTTU2LjQ0NiA2Ny43NDV2LjAwMmwuMDAzLjAwNC0uMDAzLS4wMDZabTMyLjk3Ny4zNjVjLS42NTYgMy45NzUtMi4zNDUgNy4yLTUuMTg1IDEwLjE2OGEyMS4zNjMgMjEuMzYzIDAgMCAxLTYuMjI3IDQuNjU0IDI2LjMwNSAyNi4zMDUgMCAwIDEtNC4wNjYgMS43MThjLTEwLjcwNCAzLjQ5Ni0yMS42Ni0uMzQ4LTI1LjE5Mi04LjYwMWExMy4yNyAxMy4yNyAwIDAgMS0uNzA4LTEuOTVjLTEuNTA1LTUuNDM4LS4yMjctMTEuOTYzIDMuNzY3LTE2LjA3di0uMDAzYy4yNDYtLjI2MS40OTctLjU3LjQ5Ny0uOTU3IDAtLjMyNC0uMjA2LS42NjYtLjM4NC0uOTA4LTEuMzk4LTIuMDI3LTYuMjM4LTUuNDgtNS4yNjctMTIuMTY1LjY5OC00LjgwMSA0Ljg5Ny04LjE4MyA4LjgxMy03Ljk4Mi4zMy4wMTcuNjYyLjAzNy45OTIuMDU3IDEuNjk3LjEgMy4xNzcuMzE4IDQuNTc0LjM3NiAyLjMzNy4xIDQuNDQtLjIzOSA2LjkyOS0yLjMxMy44NC0uNyAxLjUxMy0xLjMwNyAyLjY1My0xLjUuMTE5LS4wMi40MTctLjEyNyAxLjAxMy0uMS42MDguMDMzIDEuMTg2LjIgMS43MDYuNTQ2IDEuOTk2IDEuMzI5IDIuMjggNC41NDUgMi4zODMgNi44OTkuMDU4IDEuMzQzLjIyMSA0LjU5My4yNzcgNS41MjYuMTI2IDIuMTMzLjY4NyAyLjQzNCAxLjgyMiAyLjgwOC42MzguMjEgMS4yMy4zNjYgMi4xMDMuNjExIDIuNjQyLjc0MiA0LjIwOSAxLjQ5NSA1LjE5NiAyLjQ2MS41ODkuNjA1Ljg2MyAxLjI0Ny45NDcgMS44NTkuMzEyIDIuMjczLTEuNzY0IDUuMDgtNy4yNiA3LjYzMS02LjAwOCAyLjc4OS0xMy4yOTYgMy40OTUtMTguMzMyIDIuOTM0bC0xLjc2NC0uMmMtNC4wMjktLjU0Mi02LjMyNyA0LjY2NC0zLjkwOSA4LjIzIDEuNTU4IDIuMjk5IDUuODAyIDMuNzk1IDEwLjA0OCAzLjc5NSA5LjczNi4wMDIgMTcuMjE5LTQuMTU2IDIwLjAwMi03Ljc0NmEzLjcxIDMuNzEgMCAwIDAgLjIyMy0uMzE4Yy4xMzctLjIwNi4wMjQtLjMyLS4xNDctLjIwMy0yLjI3NCAxLjU1Ni0xMi4zNzUgNy43MzQtMjMuMTggNS44NzUgMCAwLTEuMzEzLS4yMTYtMi41MTEtLjY4Mi0uOTUzLS4zNy0yLjk0Ni0xLjI4Ny0zLjE4OC0zLjMzMiA4LjcyIDIuNjk2IDE0LjIxLjE0NyAxNC4yMS4xNDdhLjI3LjI3IDAgMCAwIC4xNTYtLjI2OC4yNS4yNSAwIDAgMC0uMjc2LS4yMjVzLTcuMTQ4IDEuMDU5LTEzLjktMS40MTNjLjczNS0yLjM5IDIuNjkxLTEuNTI3IDUuNjQ3LTEuMjkgNS4zMjguMzE4IDEwLjEwMy0uNDYgMTMuNjMyLTEuNDczIDMuMDU4LS44NzcgNy4wNzUtMi42MDggMTAuMTk0LTUuMDcgMS4wNTMgMi4zMTEgMS40MjQgNC44NTUgMS40MjQgNC44NTVzLjgxNS0uMTQ1IDEuNDk1LjI3NGMuNjQ0LjM5NSAxLjExNSAxLjIxOC43OTMgMy4zNDZaTTM5Ljc2NSAzMC4yNDdjMy4zNDktMy44NyA3LjQ3Mi03LjIzNSAxMS4xNjYtOS4xMjQuMTI3LS4wNjYuMjYzLjA3My4xOTQuMTk4LS4yOTQuNTMyLS44NTggMS42NjgtMS4wMzcgMi41MzItLjAyOC4xMzQuMTE4LjIzNS4yMzEuMTU4IDIuMjk4LTEuNTY3IDYuMjk1LTMuMjQ1IDkuODAxLTMuNDYuMTUxLS4wMS4yMjQuMTgzLjEwNC4yNzVhOC4zNDUgOC4zNDUgMCAwIDAtMS41NDIgMS41NDcuMTUuMTUgMCAwIDAgLjExNy4yNGMyLjQ2Mi4wMTcgNS45MzMuODc4IDguMTk0IDIuMTQ3LjE1NC4wODYuMDQ1LjM4Mi0uMTI2LjM0My0zLjQyMy0uNzg1LTkuMDI2LTEuMzgtMTQuODQ1LjA0LTUuMTk1IDEuMjY3LTkuMTYgMy4yMjQtMTIuMDU0IDUuMzI4LS4xNDYuMTA2LS4zMjItLjA4Ny0uMjAzLS4yMjRabS0xNy40IDE4LjQwN2MtMy4wMzMuNTktNS43MDYgMi4zMDgtNy4zNCA0LjY4Mi0uOTc3LS44MTUtMi43OTctMi4zOTItMy4xMTgtMy4wMDYtMi42MS00Ljk1NSAyLjg0OC0xNC41ODggNi42Ni0yMC4wMjggOS40Mi0xMy40NDQgMjQuMTc2LTIzLjYyIDMxLjAwNy0yMS43NzQgMS4xMS4zMTQgNC43ODggNC41NzggNC43ODggNC41NzhzLTYuODI4IDMuNzg5LTEzLjE2IDkuMDdjLTguNTMyIDYuNTY5LTE0Ljk3NyAxNi4xMTctMTguODM3IDI2LjQ3OFptNS4wOTUgMjIuNzM1Yy0uNDYyLjA3OC0uOTMuMTExLTEuNC4wOTktNC41NjItLjEyMy05LjQ5LTQuMjMtOS45OC05LjEwMi0uNTQyLTUuMzg0IDIuMjEtOS41MjkgNy4wODEtMTAuNTFhOC4yOSA4LjI5IDAgMCAxIDIuMDQ1LS4xNDdjMi43My4xNSA2Ljc1MSAyLjI0NiA3LjY3IDguMTkxLjgxNCA1LjI2Ni0uNDc5IDEwLjYyOC01LjQxNiAxMS40N1ptNjEuODA5LTkuNTM0Yy0uMDQtLjEzOC0uMjk0LTEuMDctLjY0NC0yLjE5YTE3LjczOCAxNy43MzggMCAwIDAtLjcxMi0xLjkxMmMxLjQwMy0yLjEgMS40MjktMy45OCAxLjI0Mi01LjA0NC0uMi0xLjMxOS0uNzQ4LTIuNDQzLTEuODU1LTMuNjA1cy0zLjM3LTIuMzUyLTYuNTUyLTMuMjQ1Yy0uMzY0LS4xMDItMS41NjQtLjQzMi0xLjY3LS40NjQtLjAwOC0uMDY5LS4wODctMy45MzUtLjE2LTUuNTk1LS4wNTMtMS4yLS4xNTYtMy4wNzMtLjczNy00LjkxOC0uNjkyLTIuNDk3LTEuOS00LjY4My0zLjQwNi02LjA4IDQuMTU4LTQuMzEgNi43NTItOS4wNTcgNi43NDYtMTMuMTMtLjAxMi03LjgzMS05LjYzLTEwLjItMjEuNDgyLTUuMjkzbC0yLjUxMiAxLjA2NmMtLjAxLS4wMS00LjU0LTQuNDU0LTQuNjA4LTQuNTE0QzM5LjQwNS00Ljg1Ny0yLjg0NyA0Mi4xMDggMTAuNjYyIDUzLjUxNGwyLjk1MiAyLjVjLS43NjYgMS45ODUtMS4wNjcgNC4yNTctLjgyIDYuNzAxLjMxNSAzLjE0IDEuOTM0IDYuMTQ5IDQuNTU5IDguNDc0IDIuNDkxIDIuMjA4IDUuNzY3IDMuNjA1IDguOTQ2IDMuNjAyIDUuMjU3IDEyLjExNCAxNy4yNjggMTkuNTQ2IDMxLjM1MSAxOS45NjQgMTUuMTA3LjQ0OSAyNy43ODgtNi42NCAzMy4xMDItMTkuMzczLjM0OC0uODk0IDEuODIzLTQuOTIgMS44MjMtOC40NzUgMC0zLjU3My0yLjAyLTUuMDUzLTMuMzA2LTUuMDUzWiIvPjwvZz48ZGVmcz48Y2xpcFBhdGggaWQ9ImEiPjxwYXRoIGQ9Ik04IDVoODQuNjZ2ODkuODNIOHoiLz48L2NsaXBQYXRoPjwvZGVmcz48L3N2Zz4='
197 - );
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();
198 236 }
199 -add_action( 'admin_menu', 'mailchimp_sf_add_pages' );
200 237
201 238 /**
202 239 * Request handler
203 240 *
@@ -216,9 +253,9 @@
216 253 wp_die( 'Cheatin&rsquo; huh?' );
217 254 }
218 255
219 256 // erase auth information
220 - $options = array( 'mc_api_key', 'mailchimp_sf_access_token', 'mc_datacenter', 'mailchimp_sf_auth_error', 'mailchimp_sf_waiting_for_login', 'mc_sopresto_user', 'mc_sopresto_public_key', 'mc_sopresto_secret_key', 'mc_list_id' );
257 + $options = array( 'mc_api_key', 'mailchimp_sf_access_token', 'mc_datacenter', 'mailchimp_sf_auth_error', 'mailchimp_sf_waiting_for_login' );
221 258 mailchimp_sf_delete_options( $options );
222 259 break;
223 260 case 'change_form_settings':
224 261 if (
@@ -231,32 +268,8 @@
231 268
232 269 // Update the form settings
233 270 mailchimp_sf_save_general_form_settings();
234 271 break;
235 - case 'mc_submit_signup_form':
236 - // Validate nonce
237 - if (
238 - ! isset( $_POST['_mc_submit_signup_form_nonce'] ) ||
239 - ! wp_verify_nonce( sanitize_key( $_POST['_mc_submit_signup_form_nonce'] ), 'mc_submit_signup_form' )
240 - ) {
241 - wp_die( 'Cheatin&rsquo; huh?' );
242 - }
243 -
244 - // Attempt the signup
245 - mailchimp_sf_signup_submit();
246 -
247 - // Do a different action for html vs. js
248 - switch ( isset( $_POST['mc_submit_type'] ) ? $_POST['mc_submit_type'] : '' ) {
249 - case 'html':
250 - /* This gets set elsewhere! */
251 - break;
252 - case 'js':
253 - if ( ! headers_sent() ) { // just in case...
254 - header( 'Last-Modified: ' . gmdate( 'D, d M Y H:i:s' ) . ' GMT', true, 200 );
255 - }
256 - echo wp_kses_post( mailchimp_sf_global_msg() );
257 - exit;
258 - }
259 272 }
260 273 }
261 274 }
262 275 add_action( 'init', 'mailchimp_sf_request_handler' );
@@ -261,60 +274,8 @@
261 274 }
262 275 add_action( 'init', 'mailchimp_sf_request_handler' );
263 276
264 277 /**
265 - * Migrate Sopresto
266 - *
267 - * @return void
268 - */
269 -function mailchimp_sf_migrate_sopresto() {
270 - $sopresto = get_option( 'mc_sopresto_secret_key' );
271 - if ( ! $sopresto ) {
272 - return;
273 - }
274 -
275 - // Talk to Sopresto, make exchange, delete old sopresto things.
276 - $body = array(
277 - 'public_key' => get_option( 'mc_sopresto_public_key' ),
278 - 'hash' => sha1( get_option( 'mc_sopresto_public_key' ) . get_option( 'mc_sopresto_secret_key' ) ),
279 - );
280 -
281 - $url = 'https://sopresto.socialize-this.com/mailchimp/exchange';
282 - $args = array(
283 - 'method' => 'POST',
284 - 'timeout' => 500,
285 - 'redirection' => 5,
286 - 'httpversion' => '1.0',
287 - 'user-agent' => 'Mailchimp WordPress Plugin/' . get_bloginfo( 'url' ),
288 - 'body' => $body,
289 - );
290 -
291 - // post to sopresto
292 - $key = wp_remote_post( $url, $args );
293 - if ( ! is_wp_error( $key ) && 200 === $key['response']['code'] ) {
294 - $key = json_decode( $key['body'] );
295 - try {
296 - $api = new MailChimp_API( $key->response );
297 - } catch ( Exception $e ) {
298 - $msg = '<strong class="mc_error_msg">' . $e->getMessage() . '</strong>';
299 - mailchimp_sf_global_msg( $msg );
300 - return;
301 - }
302 -
303 - $verify = mailchimp_sf_verify_key( $api );
304 -
305 - // something went wrong with the key that we had
306 - if ( is_wp_error( $verify ) ) {
307 - return;
308 - }
309 -
310 - delete_option( 'mc_sopresto_public_key' );
311 - delete_option( 'mc_sopresto_secret_key' );
312 - delete_option( 'mc_sopresto_user' );
313 - }
314 -}
315 -
316 -/**
317 278 * Update merge fields
318 279 *
319 280 * @return void
320 281 */
@@ -390,17 +351,15 @@
390 351 }
391 352
392 353 /**
393 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
394 358 **/
395 359 function mailchimp_sf_delete_setup() {
396 360 $options = array(
397 361 'mc_user_id',
398 - 'mc_sopresto_user',
399 - 'mc_sopresto_public_key',
400 - 'mc_sopresto_secret_key',
401 - 'mc_use_javascript',
402 - 'mc_use_datepicker',
403 362 'mc_use_unsub_link',
404 363 'mc_list_id',
405 364 'mc_list_name',
406 365 'mc_interest_groups',
@@ -426,14 +385,19 @@
426 385 mailchimp_sf_delete_options( $options );
427 386 }
428 387
429 388 /**
430 - * 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
431 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 + *
432 396 * @param mixed $msg Message
433 397 * @return string/bool depending on get/set
434 398 */
435 -function mailchimp_sf_global_msg( $msg = null ) {
399 +function mailchimp_sf_frontend_msg( $msg = null ) {
436 400 global $mcsf_msgs;
437 401
438 402 // Make sure we're formed properly
439 403 if ( ! is_array( $mcsf_msgs ) ) {
@@ -450,8 +414,20 @@
450 414 return true;
451 415 }
452 416
453 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 +/**
454 430 * Sets the default options for the option form
455 431 *
456 432 * @param string $list_name The Mailchimp list name.
457 433 * @return void
@@ -459,17 +435,11 @@
459 435 function mailchimp_sf_set_form_defaults( $list_name = '' ) {
460 436 update_option( 'mc_header_content', esc_html__( 'Sign up for', 'mailchimp' ) . ' ' . $list_name );
461 437 update_option( 'mc_submit_text', esc_html__( 'Subscribe', 'mailchimp' ) );
462 438
463 - update_option( 'mc_use_datepicker', 'on' );
464 439 update_option( 'mc_custom_style', 'off' );
465 - update_option( 'mc_use_javascript', 'on' );
466 440 update_option( 'mc_double_optin', true );
467 441 update_option( 'mc_use_unsub_link', 'off' );
468 - update_option( 'mc_header_border_width', '1' );
469 - update_option( 'mc_header_border_color', 'E3E3E3' );
470 - update_option( 'mc_header_background', 'FFFFFF' );
471 - update_option( 'mc_header_text_color', 'CC6600' );
472 442
473 443 update_option( 'mc_form_border_width', '1' );
474 444 update_option( 'mc_form_border_color', 'E0E0E0' );
475 445 update_option( 'mc_form_background', 'FFFFFF' );
@@ -481,71 +451,50 @@
481 451 *
482 452 * @return void
483 453 **/
484 454 function mailchimp_sf_save_general_form_settings() {
485 -
486 - // IF NOT DEV MODE
487 - if ( isset( $_POST['mc_use_javascript'] ) ) {
488 - update_option( 'mc_use_javascript', 'on' );
489 - $msg = '<p class="success_msg">' . esc_html__( 'Fancy Javascript submission turned On!', 'mailchimp' ) . '</p>';
490 - mailchimp_sf_global_msg( $msg );
491 - } elseif ( get_option( 'mc_use_javascript' ) !== 'off' ) {
492 - update_option( 'mc_use_javascript', 'off' );
493 - $msg = '<p class="success_msg">' . esc_html__( 'Fancy Javascript submission turned Off!', 'mailchimp' ) . '</p>';
494 - mailchimp_sf_global_msg( $msg );
495 - }
496 -
497 - if ( isset( $_POST['mc_use_datepicker'] ) ) {
498 - update_option( 'mc_use_datepicker', 'on' );
499 - $msg = '<p class="success_msg">' . esc_html__( 'Datepicker turned On!', 'mailchimp' ) . '</p>';
500 - mailchimp_sf_global_msg( $msg );
501 - } elseif ( get_option( 'mc_use_datepicker' ) !== 'off' ) {
502 - update_option( 'mc_use_datepicker', 'off' );
503 - $msg = '<p class="success_msg">' . esc_html__( 'Datepicker turned Off!', 'mailchimp' ) . '</p>';
504 - mailchimp_sf_global_msg( $msg );
505 - }
506 -
455 + // phpcs:disable WordPress.Security.NonceVerification.Missing -- Nonce check is already done in the mailchimp_sf_request_handler() function.
507 456 /*Enable double optin toggle*/
508 457 if ( isset( $_POST['mc_double_optin'] ) ) {
509 458 update_option( 'mc_double_optin', true );
510 - $msg = '<p class="success_msg">' . esc_html__( 'Double opt-in turned On!', 'mailchimp' ) . '</p>';
511 - mailchimp_sf_global_msg( $msg );
459 + $msg = esc_html__( 'Double opt-in turned On!', 'mailchimp' );
460 + admin_notice_success( $msg );
512 461 } elseif ( get_option( 'mc_double_optin' ) !== false ) {
513 462 update_option( 'mc_double_optin', false );
514 - $msg = '<p class="success_msg">' . esc_html__( 'Double opt-in turned Off!', 'mailchimp' ) . '</p>';
515 - mailchimp_sf_global_msg( $msg );
463 + $msg = esc_html__( 'Double opt-in turned Off!', 'mailchimp' );
464 + admin_notice_success( $msg );
516 465 }
517 466
518 467 /* NUKE the CSS! */
519 468 if ( isset( $_POST['mc_nuke_all_styles'] ) ) {
520 469 update_option( 'mc_nuke_all_styles', true );
521 - $msg = '<p class="success_msg">' . esc_html__( 'Mailchimp CSS turned Off!', 'mailchimp' ) . '</p>';
522 - mailchimp_sf_global_msg( $msg );
470 + $msg = esc_html__( 'Mailchimp CSS turned Off!', 'mailchimp' );
471 + admin_notice_success( $msg );
523 472 } elseif ( get_option( 'mc_nuke_all_styles' ) !== false ) {
524 473 update_option( 'mc_nuke_all_styles', false );
525 - $msg = '<p class="success_msg">' . esc_html__( 'Mailchimp CSS turned On!', 'mailchimp' ) . '</p>';
526 - mailchimp_sf_global_msg( $msg );
474 + $msg = esc_html__( 'Mailchimp CSS turned On!', 'mailchimp' );
475 + admin_notice_success( $msg );
527 476 }
528 477
529 478 /* Update existing */
530 479 if ( isset( $_POST['mc_update_existing'] ) ) {
531 480 update_option( 'mc_update_existing', true );
532 - $msg = '<p class="success_msg">' . esc_html__( 'Update existing subscribers turned On!' ) . '</p>';
533 - mailchimp_sf_global_msg( $msg );
481 + $msg = esc_html__( 'Update existing subscribers turned On!', 'mailchimp' );
482 + admin_notice_success( $msg );
534 483 } elseif ( get_option( 'mc_update_existing' ) !== false ) {
535 484 update_option( 'mc_update_existing', false );
536 - $msg = '<p class="success_msg">' . esc_html__( 'Update existing subscribers turned Off!' ) . '</p>';
537 - mailchimp_sf_global_msg( $msg );
485 + $msg = esc_html__( 'Update existing subscribers turned Off!', 'mailchimp' );
486 + admin_notice_success( $msg );
538 487 }
539 488
540 489 if ( isset( $_POST['mc_use_unsub_link'] ) ) {
541 490 update_option( 'mc_use_unsub_link', 'on' );
542 - $msg = '<p class="success_msg">' . esc_html__( 'Unsubscribe link turned On!', 'mailchimp' ) . '</p>';
543 - mailchimp_sf_global_msg( $msg );
491 + $msg = esc_html__( 'Unsubscribe link turned On!', 'mailchimp' );
492 + admin_notice_success( $msg );
544 493 } elseif ( get_option( 'mc_use_unsub_link' ) !== 'off' ) {
545 494 update_option( 'mc_use_unsub_link', 'off' );
546 - $msg = '<p class="success_msg">' . esc_html__( 'Unsubscribe link turned Off!', 'mailchimp' ) . '</p>';
547 - mailchimp_sf_global_msg( $msg );
495 + $msg = esc_html__( 'Unsubscribe link turned Off!', 'mailchimp' );
496 + admin_notice_success( $msg );
548 497 }
549 498
550 499 $content = isset( $_POST['mc_header_content'] ) ? wp_kses_post( wp_unslash( $_POST['mc_header_content'] ) ) : '';
551 500 $content = str_replace( "\r\n", '<br/>', $content );
@@ -592,9 +541,9 @@
592 541 $mv = get_option( 'mc_merge_vars' );
593 542 if ( is_array( $mv ) ) {
594 543 foreach ( $mv as $mv_var ) {
595 544 $opt = 'mc_mv_' . $mv_var['tag'];
596 - if ( isset( $_POST[ $opt ] ) || 'Y' === $mv_var['required'] ) {
545 + if ( isset( $_POST[ $opt ] ) || true === (bool) $mv_var['required'] ) {
597 546 update_option( $opt, 'on' );
598 547 } else {
599 548 update_option( $opt, 'off' );
600 549 }
@@ -600,10 +549,11 @@
600 549 }
601 550 }
602 551 }
603 552
604 - $msg = '<p class="success_msg">' . esc_html__( 'Successfully Updated your List Subscribe Form Settings!', 'mailchimp' ) . '</p>';
605 - mailchimp_sf_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
606 556 }
607 557
608 558 /**
609 559 * Sees if the user changed the list, and updates options accordingly
@@ -612,24 +562,24 @@
612 562 if ( ! isset( $_POST['mc_list_id'] ) ) {
613 563 return;
614 564 }
615 565
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 + }
573 +
616 574 if ( empty( $_POST['mc_list_id'] ) ) {
617 - $msg = '<p class="error_msg">' . esc_html__( 'Please choose a valid list', 'mailchimp' ) . '</p>';
618 - mailchimp_sf_global_msg( $msg );
575 + $msg = esc_html__( 'Please choose a valid list', 'mailchimp' );
576 + admin_notice_error( $msg );
619 577 return;
620 578 }
621 579
622 - // Simple permission check before going through all this
623 - if ( ! current_user_can( MCSF_CAP_THRESHOLD ) ) { return; }
624 -
625 - $api = mailchimp_sf_get_api();
626 - if ( ! $api ) { return; }
627 -
628 - // we *could* support paging, but few users have that many lists (and shouldn't)
629 - $lists = $api->get( 'lists', 100, array( 'fields' => 'lists.id,lists.name,lists.email_type_option' ) );
630 -
631 - if ( ! isset( $lists['lists'] ) || is_wp_error( $lists['lists'] ) ) {
580 + $lists = mailchimp_sf_get_lists();
581 + if ( is_wp_error( $lists ) || ! isset( $lists['lists'] ) ) {
632 582 return;
633 583 }
634 584
635 585 $lists = $lists['lists'];
@@ -645,8 +595,17 @@
645 595 $list_id = sanitize_text_field( wp_unslash( $_POST['mc_list_id'] ) );
646 596 $list_name = $list['name'];
647 597 $list_key = $key;
648 598 }
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 + }
649 608 }
650 609
651 610 $orig_list = get_option( 'mc_list_id' );
652 611 if ( '' !== $list_id ) {
@@ -672,19 +631,21 @@
672 631 /* translators: %s: count (number) */
673 632 $igs_text .= sprintf( esc_html__( 'and %s Sets of Interest Groups', 'mailchimp' ), count( $igs ) );
674 633 }
675 634
676 - $msg = '<p class="success_msg">' .
677 - sprintf(
678 - /* translators: %s: count (number) */
679 - __( '<b>Success!</b> Loaded and saved the info for %d Merge Variables', 'mailchimp' ) . $igs_text,
680 - count( $mv )
681 - ) . ' ' .
682 - esc_html__( 'from your list' ) . ' "' . $list_name . '"<br/><br/>' .
683 - esc_html__( 'Now you should either Turn On the Mailchimp Widget or change your options below, then turn it on.', 'mailchimp' ) . '</p>';
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' );
684 642
685 - mailchimp_sf_global_msg( $msg );
643 + admin_notice_success( $msg );
686 644 }
645 +
646 + // Update the lists option.
647 + update_option( 'mailchimp_sf_lists', $lists );
687 648 }
688 649 }
689 650
690 651 /**
@@ -691,11 +652,12 @@
691 652 * Get merge vars
692 653 *
693 654 * @param string $list_id List ID
694 655 * @param bool $new_list Whether this is a new list
656 + * @param bool $update_option Whether to update the option
695 657 * @return array
696 658 */
697 -function mailchimp_sf_get_merge_vars( $list_id, $new_list ) {
659 +function mailchimp_sf_get_merge_vars( $list_id, $new_list, $update_option = true ) {
698 660 $api = mailchimp_sf_get_api();
699 661 $mv = $api->get( 'lists/' . $list_id . '/merge-fields', 80 );
700 662
701 663 // if we get an error back from the api, exit this process.
@@ -703,14 +665,23 @@
703 665 return;
704 666 }
705 667
706 668 $mv['merge_fields'] = mailchimp_sf_add_email_field( $mv['merge_fields'] );
707 - update_option( 'mc_merge_vars', $mv['merge_fields'] );
669 + if ( $update_option ) {
670 + update_option( 'mc_merge_vars', $mv['merge_fields'] );
671 + }
672 +
708 673 foreach ( $mv['merge_fields'] as $mv_var ) {
709 674 $opt = 'mc_mv_' . $mv_var['tag'];
710 - // turn them all on by default
711 675 if ( $new_list ) {
712 - update_option( $opt, 'on' );
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 + }
713 684 }
714 685 }
715 686 return $mv['merge_fields'];
716 687 }
@@ -739,11 +710,12 @@
739 710 * Get interest categories
740 711 *
741 712 * @param string $list_id List ID
742 713 * @param bool $new_list Whether this is a new list
714 + * @param bool $update_option Whether to update the option
743 715 * @return array
744 716 */
745 -function mailchimp_sf_get_interest_categories( $list_id, $new_list ) {
717 +function mailchimp_sf_get_interest_categories( $list_id, $new_list, $update_option = true ) {
746 718 $api = mailchimp_sf_get_api();
747 719 $igs = $api->get( 'lists/' . $list_id . '/interest-categories', 60 );
748 720
749 721 // if we get an error back from the api, exis
@@ -764,19 +736,14 @@
764 736 }
765 737 ++$key;
766 738 }
767 739 }
768 - update_option( 'mc_interest_groups', $igs['categories'] );
769 - return $igs['categories'];
770 -}
771 740
741 + if ( $update_option ) {
742 + update_option( 'mc_interest_groups', $igs['categories'] );
743 + }
772 744
773 -/**
774 - * Outputs the Settings/Options page
775 - */
776 -function mailchimp_sf_setup_page() {
777 - $path = plugin_dir_path( __FILE__ );
778 - require_once $path . '/includes/admin/templates/settings.php';
745 + return $igs['categories'];
779 746 }
780 747
781 748 /**
782 749 * Register the widget.
@@ -802,151 +769,17 @@
802 769 }
803 770 add_shortcode( 'mailchimpsf_form', 'mailchimp_sf_shortcode' );
804 771
805 772 /**
806 - * Add block
807 - *
808 - * @return void
809 - */
810 -function mailchimp_sf_block() {
811 - // In line with conditional register of the widget.
812 - if ( ! mailchimp_sf_get_api() ) {
813 - return;
814 - }
815 -
816 - $blocks_dist_path = plugin_dir_path( __FILE__ ) . 'dist/blocks/';
817 -
818 - if ( file_exists( $blocks_dist_path ) ) {
819 - $block_json_files = glob( $blocks_dist_path . '*/block.json' );
820 - foreach ( $block_json_files as $filename ) {
821 - $block_folder = dirname( $filename );
822 - register_block_type( $block_folder );
823 - }
824 - }
825 -
826 - $data = 'window.MAILCHIMP_ADMIN_SETTINGS_URL = "' . esc_js( esc_url( admin_url( 'admin.php?page=mailchimp_sf_options' ) ) ) . '";';
827 - wp_add_inline_script( 'mailchimp-mailchimp-editor-script', $data, 'before' );
828 -
829 - ob_start();
830 - require_once MCSF_DIR . '/views/css/frontend.php';
831 - $data = ob_get_clean();
832 - wp_add_inline_style( 'mailchimp-mailchimp-editor-style', $data );
833 -}
834 -
835 -add_action( 'init', 'mailchimp_sf_block' );
836 -
837 -/**
838 - * Attempts to signup a user, per the $_POST args.
839 - *
840 - * This sets a global message, that is then used in the widget
841 - * output to retrieve and display that message.
842 - *
843 - * @return bool
844 - */
845 -function mailchimp_sf_signup_submit() {
846 - $mv = get_option( 'mc_merge_vars', array() );
847 - $mv_tag_keys = array();
848 -
849 - $igs = get_option( 'mc_interest_groups', array() );
850 -
851 - $list_id = get_option( 'mc_list_id' );
852 - $email = isset( $_POST['mc_mv_EMAIL'] ) ? wp_strip_all_tags( wp_unslash( $_POST['mc_mv_EMAIL'] ) ) : '';
853 -
854 - $merge = mailchimp_sf_merge_submit( $mv );
855 -
856 - // Catch errors and fail early.
857 - if ( is_wp_error( $merge ) ) {
858 - $msg = '<strong class="mc_error_msg">' . $merge->get_error_message() . '</strong>';
859 - mailchimp_sf_global_msg( $msg );
860 -
861 - return false;
862 - }
863 -
864 - // Head back to the beginning of the merge vars array
865 - reset( $mv );
866 - // Ensure we have an array
867 - $igs = ! is_array( $igs ) ? array() : $igs;
868 - $igs = mailchimp_sf_groups_submit( $igs );
869 -
870 - // Clear out empty merge vars
871 - $merge = mailchimp_sf_merge_remove_empty( $merge );
872 - if ( isset( $_POST['email_type'] ) && in_array( $_POST['email_type'], array( 'text', 'html', 'mobile' ), true ) ) {
873 - $email_type = sanitize_text_field( wp_unslash( $_POST['email_type'] ) );
874 - } else {
875 - $email_type = 'html';
876 - }
877 -
878 - $api = mailchimp_sf_get_api();
879 - if ( ! $api ) {
880 - $url = mailchimp_sf_signup_form_url();
881 - $error = sprintf(
882 - '<strong class="mc_error_msg">%s</strong>',
883 - wp_kses(
884 - sprintf(
885 - /* translators: 1: email address 2: url */
886 - __(
887 - 'We encountered a problem adding %1$s to the list. Please <a href="%2$s">sign up here.</a>',
888 - 'mailchimp'
889 - ),
890 - esc_html( $email ),
891 - esc_url( $url )
892 - ),
893 - [
894 - 'a' => [
895 - 'href' => [],
896 - ],
897 - ]
898 - )
899 - );
900 - mailchimp_sf_global_msg( $error );
901 - return false;
902 - }
903 -
904 - $url = 'lists/' . $list_id . '/members/' . md5( strtolower( $email ) );
905 - $status = mailchimp_sf_check_status( $url );
906 -
907 - // If update existing is turned off and the subscriber exists, error out.
908 - if ( get_option( 'mc_update_existing' ) === false && 'subscribed' === $status ) {
909 - $msg = esc_html__( 'This email address is already subscribed to the list.', 'mailchimp' );
910 - $error = new WP_Error( 'mailchimp-update-existing', $msg );
911 - mailchimp_sf_global_msg( '<strong class="mc_error_msg">' . $msg . '</strong>' );
912 - return false;
913 - }
914 -
915 - $body = mailchimp_sf_subscribe_body( $merge, $igs, $email_type, $email, $status, get_option( 'mc_double_optin' ) );
916 - $retval = $api->post( $url, $body, 'PUT' );
917 -
918 - // If we have errors, then show them
919 - if ( is_wp_error( $retval ) ) {
920 - $msg = '<strong class="mc_error_msg">' . $retval->get_error_message() . '</strong>';
921 - mailchimp_sf_global_msg( $msg );
922 - return false;
923 - }
924 -
925 - if ( 'subscribed' === $retval['status'] ) {
926 - $esc = esc_html__( 'Success, you\'ve been signed up.', 'mailchimp' );
927 - $msg = "<strong class='mc_success_msg'>{$esc}</strong>";
928 - } else {
929 - $esc = esc_html__( 'Success, you\'ve been signed up! Please look for our confirmation email.', 'mailchimp' );
930 - $msg = "<strong class='mc_success_msg'>{$esc}</strong>";
931 - }
932 -
933 - // Set our global message
934 - mailchimp_sf_global_msg( $msg );
935 -
936 - return true;
937 -}
938 -
939 -/**
940 773 * Cleans up merge fields and interests to make them
941 774 * API 3.0-friendly.
942 775 *
943 - * @param [type] $merge Merge fields
944 - * @param [type] $igs Interest groups
945 - * @param string $email_type Email type
946 - * @param string $email Email
947 - * @param string $status Status
948 - * @param bool $double_optin Whether this is double optin
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.
949 782 * @return stdClass
950 783 */
951 784 function mailchimp_sf_subscribe_body( $merge, $igs, $email_type, $email, $status, $double_optin ) {
952 785 $body = new stdClass();
@@ -952,29 +785,31 @@
952 785 $body = new stdClass();
953 786 $body->email_address = $email;
954 787 $body->email_type = $email_type;
955 788 $body->merge_fields = $merge;
789 +
956 790 if ( ! empty( $igs ) ) {
957 791 $body->interests = $igs;
958 792 }
959 793
960 - if ( 'subscribed' !== $status ) {
961 - // single opt-in that covers new subscribers
962 - if ( false === ! $status && $double_optin ) {
963 - $body->status = 'subscribed';
964 - } else {
965 - // anyone else
966 - $body->status = 'pending';
967 - }
794 + // Early return for already subscribed users
795 + if ( 'subscribed' === $status ) {
796 + return $body;
968 797 }
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';
803 +
969 804 return $body;
970 805 }
971 806
972 807 /**
973 - * Check status.
808 + * Check the status of a subscriber in the list.
974 809 *
975 - * @param string $endpoint Endpoint.
976 - * @return string
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.
977 812 */
978 813 function mailchimp_sf_check_status( $endpoint ) {
979 814 $endpoint .= '?fields=status';
980 815 $api = mailchimp_sf_get_api();
@@ -985,211 +820,8 @@
985 820 return $subscriber['status'];
986 821 }
987 822
988 823 /**
989 - * Merge submit
990 - *
991 - * @param array $mv Merge Vars
992 - * @return mixed
993 - */
994 -function mailchimp_sf_merge_submit( $mv ) {
995 - // Loop through our Merge Vars, and if they're empty, but required, then print an error, and mark as failed
996 - $merge = new stdClass();
997 - foreach ( $mv as $mv_var ) {
998 - // We also want to create an array where the keys are the tags for easier validation later
999 - $tag = $mv_var['tag'];
1000 - $mv_tag_keys[ $tag ] = $mv_var;
1001 -
1002 - $opt = 'mc_mv_' . $tag;
1003 -
1004 - $opt_val = isset( $_POST[ $opt ] ) ? map_deep( stripslashes_deep( $_POST[ $opt ] ), 'sanitize_text_field' ) : '';
1005 -
1006 - // Handle phone number logic
1007 - if ( isset( $mv_var['options']['phone_format'] ) && 'phone' === $mv_var['type'] && 'US' === $mv_var['options']['phone_format'] ) {
1008 - $opt_val = mailchimp_sf_merge_validate_phone( $opt_val, $mv_var );
1009 - if ( is_wp_error( $opt_val ) ) {
1010 - return $opt_val;
1011 - }
1012 - } elseif ( is_array( $opt_val ) && 'address' === $mv_var['type'] ) { // Handle address logic
1013 - $validate = mailchimp_sf_merge_validate_address( $opt_val, $mv_var );
1014 - if ( is_wp_error( $validate ) ) {
1015 - return $validate;
1016 - }
1017 -
1018 - if ( $validate ) {
1019 - $merge->$tag = $validate;
1020 - }
1021 - continue;
1022 -
1023 - } elseif ( is_array( $opt_val ) ) {
1024 - $keys = array_keys( $opt_val );
1025 - $val = new stdClass();
1026 - foreach ( $keys as $key ) {
1027 - $val->$key = $opt_val[ $key ];
1028 - }
1029 - $opt_val = $val;
1030 - }
1031 -
1032 - if ( 'Y' === $mv_var['required'] && trim( $opt_val ) === '' ) {
1033 - /* translators: %s: field name */
1034 - $message = sprintf( esc_html__( 'You must fill in %s.', 'mailchimp' ), esc_html( $mv_var['name'] ) );
1035 - $error = new WP_Error( 'missing_required_field', $message );
1036 - return $error;
1037 - } elseif ( 'EMAIL' !== $tag ) {
1038 - $merge->$tag = $opt_val;
1039 - }
1040 - }
1041 - return $merge;
1042 -}
1043 -
1044 -/**
1045 - * Validate phone
1046 - *
1047 - * @param array $opt_val Option value
1048 - * @param array $data Data
1049 - * @return void
1050 - */
1051 -function mailchimp_sf_merge_validate_phone( $opt_val, $data ) {
1052 - // This filters out all 'falsey' elements
1053 - $opt_val = array_filter( $opt_val );
1054 - // If they weren't all empty
1055 - if ( ! $opt_val ) {
1056 - return;
1057 - }
1058 -
1059 - $opt_val = implode( '-', $opt_val );
1060 - if ( strlen( $opt_val ) < 12 ) {
1061 - $opt_val = '';
1062 - }
1063 -
1064 - if ( ! preg_match( '/[0-9]{0,3}-[0-9]{0,3}-[0-9]{0,4}/A', $opt_val ) ) {
1065 - /* translators: %s: field name */
1066 - $message = sprintf( esc_html__( '%s must consist of only numbers', 'mailchimp' ), esc_html( $data['name'] ) );
1067 - $error = new WP_Error( 'mc_phone_validation', $message );
1068 - return $error;
1069 - }
1070 -
1071 - return $opt_val;
1072 -}
1073 -
1074 -/**
1075 - * Validate address
1076 - *
1077 - * @param array $opt_val Option value
1078 - * @param array $data Data
1079 - * @return mixed
1080 - */
1081 -function mailchimp_sf_merge_validate_address( $opt_val, $data ) {
1082 - if ( 'Y' === $data['required'] ) {
1083 - if ( empty( $opt_val['addr1'] ) || empty( $opt_val['city'] ) ) {
1084 - /* translators: %s: field name */
1085 - $message = sprintf( esc_html__( 'You must fill in %s.', 'mailchimp' ), esc_html( $data['name'] ) );
1086 - $error = new WP_Error( 'invalid_address_merge', $message );
1087 - return $error;
1088 - }
1089 - } elseif ( empty( $opt_val['addr1'] ) || empty( $opt_val['city'] ) ) {
1090 - return false;
1091 - }
1092 -
1093 - $merge = new stdClass();
1094 - $merge->addr1 = $opt_val['addr1'];
1095 - $merge->addr2 = $opt_val['addr2'];
1096 - $merge->city = $opt_val['city'];
1097 - $merge->state = $opt_val['state'];
1098 - $merge->zip = $opt_val['zip'];
1099 - $merge->country = $opt_val['country'];
1100 - return $merge;
1101 -}
1102 -
1103 -/**
1104 - * Merge remove empty
1105 - *
1106 - * @param stdObj $merge Merge
1107 - * @return stdObj
1108 - */
1109 -function mailchimp_sf_merge_remove_empty( $merge ) {
1110 - foreach ( $merge as $k => $v ) {
1111 - if ( is_object( $v ) && empty( $v ) ) {
1112 - unset( $merge->$k );
1113 - } elseif ( ( is_string( $v ) && trim( $v ) === '' ) || is_null( $v ) ) {
1114 - unset( $merge->$k );
1115 - }
1116 - }
1117 -
1118 - return $merge;
1119 -}
1120 -
1121 -/**
1122 - * Groups submit
1123 - *
1124 - * @param array $igs Interest groups
1125 - * @return stdClass
1126 - */
1127 -function mailchimp_sf_groups_submit( $igs ) {
1128 - $groups = mailchimp_sf_set_all_groups_to_false();
1129 -
1130 - if ( empty( $igs ) ) {
1131 - return new StdClass();
1132 - }
1133 -
1134 - // get groups and ids
1135 - // set all to false
1136 -
1137 - foreach ( $igs as $ig ) {
1138 - $ig_id = $ig['id'];
1139 - if ( get_option( 'mc_show_interest_groups_' . $ig_id ) === 'on' && 'hidden' !== $ig['type'] ) {
1140 - switch ( $ig['type'] ) {
1141 - case 'dropdown':
1142 - case 'radio':
1143 - // there can only be one value submitted for radio/dropdowns, so use that at the group id.
1144 - if ( isset( $_POST['group'][ $ig_id ] ) && ! empty( $_POST['group'][ $ig_id ] ) ) {
1145 - $value = sanitize_text_field( wp_unslash( $_POST['group'][ $ig_id ] ) );
1146 - $groups->$value = true;
1147 - }
1148 - break;
1149 - case 'checkboxes':
1150 - if ( isset( $_POST['group'][ $ig_id ] ) ) {
1151 - $ig_ids = array_map(
1152 - 'sanitize_text_field',
1153 - array_keys(
1154 - stripslashes_deep( $_POST['group'][ $ig_id ] ) // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- ignoring becuase this is sanitized through array_map above
1155 - )
1156 - );
1157 - foreach ( $ig_ids as $id ) {
1158 - $groups->$id = true;
1159 - }
1160 - }
1161 - break;
1162 - default:
1163 - // Nothing
1164 - break;
1165 - }
1166 - }
1167 - }
1168 - return $groups;
1169 -}
1170 -
1171 -/**
1172 - * Set all groups to false
1173 - *
1174 - * @return StdClass
1175 - */
1176 -function mailchimp_sf_set_all_groups_to_false() {
1177 - $toreturn = new StdClass();
1178 -
1179 - foreach ( get_option( 'mc_interest_groups' ) as $grouping ) {
1180 - if ( 'hidden' !== $grouping['type'] ) {
1181 - foreach ( $grouping['groups'] as $group ) {
1182 - $id = $group['id'];
1183 - $toreturn->$id = false;
1184 - }
1185 - }
1186 - }
1187 -
1188 - return $toreturn;
1189 -}
1190 -
1191 -/**
1192 824 * Verify key
1193 825 *
1194 826 * @param MailChimp_API $api API instance
1195 827 * @return mixed
@@ -1229,21 +861,8 @@
1229 861 return $url;
1230 862 }
1231 863
1232 864 /**
1233 - * Get signup form URL.
1234 - *
1235 - * @return string
1236 - */
1237 -function mailchimp_sf_signup_form_url() {
1238 - $dc = get_option( 'mc_datacenter' );
1239 - $user = get_option( 'mc_user' );
1240 - $list_id = get_option( 'mc_list_id' );
1241 - $url = 'http://' . $dc . '.list-manage.com/subscribe?u=' . $user['account_id'] . '&id=' . $list_id;
1242 - return $url;
1243 -}
1244 -
1245 -/**
1246 865 * Delete options
1247 866 *
1248 867 * @param array $options Options
1249 868 * @return void
@@ -1403,5 +1022,29 @@
1403 1022 * @return bool
1404 1023 */
1405 1024 function mailchimp_sf_should_display_form() {
1406 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' ) );
1407 1050 }