WPBO_MailChimp   B
last analyzed

Complexity

Total Complexity 43

Size/Duplication

Total Lines 389
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 1

Importance

Changes 2
Bugs 0 Features 1
Metric Value
wmc 43
c 2
b 0
f 1
lcom 1
cbo 1
dl 0
loc 389
rs 8.3157

12 Methods

Rating   Name   Duplication   Size   Complexity  
A instance() 0 14 3
A __clone() 0 4 1
A __wakeup() 0 4 1
A setup_options() 0 8 1
A load_mailchimp_api_wrapper() 0 10 2
B submit() 0 17 6
A is_mailchimp_ready() 0 9 3
A clean_fields() 0 21 4
C subscribe() 0 72 7
A get_lists() 0 14 2
C get_groups() 0 44 7
B has_groups() 0 17 6

How to fix   Complexity   

Complex Class

Complex classes like WPBO_MailChimp often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use WPBO_MailChimp, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * BetterOptin Provider MailChimp
4
 *
5
 * @package   BetterOptin/Provider/MailChimp
6
 * @author    ThemeAvenue <[email protected]>
7
 * @license   GPL-2.0+
8
 * @link      http://themeavenue.net
9
 * @copyright 2015 ThemeAvenue
10
 */
11
12
// If this file is called directly, abort.
13
if ( ! defined( 'WPINC' ) ) {
14
	die;
15
}
16
17
final class WPBO_MailChimp {
18
19
	/**
20
	 * @var WPBO_MailChimp $instance Holds the unique instance of the MailChimp provider
21
	 * @since 2.0
22
	 */
23
	private static $instance;
24
25
	/**
26
	 * @var string MailChimp API key
27
	 * @since 1.0
28
	 */
29
	private static $api_key;
30
31
	/**
32
	 * @var string MailChimp list ID
33
	 * @since 1.0
34
	 */
35
	private static $list_id;
36
37
	/**
38
	 * @var bool Whether or not to use double optin for new subscribers
39
	 * @since 1.0
40
	 */
41
	private static $double_optin;
42
43
	/**
44
	 * @var bool Whether to update existing contacts or add new
45
	 * @since 1.0
46
	 */
47
	private static $update;
48
49
	/**
50
	 * @var bool Whether or not to send the welcome message to new subscribers
51
	 * @since 1.0
52
	 */
53
	private static $welcome;
54
55
	/**
56
	 * @var array A list of allowed fields to be passed to MailChimp
57
	 * @since 1.0
58
	 */
59
	private static $fields;
60
61
	/**
62
	 * Instantiate and return the unique BetterOptin object
63
	 *
64
	 * @since     2.0
65
	 * @return object BetterOptin Unique instance of BetterOptin
66
	 */
67
	public static function instance() {
68
69
		if ( ! isset( self::$instance ) && ! ( self::$instance instanceof WPBO_MailChimp ) ) {
70
71
			// Instantiate
72
			self::$instance = new WPBO_MailChimp;
73
			self::$instance->setup_options();
74
			self::$instance->load_mailchimp_api_wrapper();
75
76
		}
77
78
		return self::$instance;
79
80
	}
81
82
	/**
83
	 * Throw error on object clone
84
	 *
85
	 * The whole idea of the singleton design pattern is that there is a single
86
	 * object therefore, we don't want the object to be cloned.
87
	 *
88
	 * @since 2.0
89
	 * @return void
90
	 */
91
	public function __clone() {
92
		// Cloning instances of the class is forbidden
93
		_doing_it_wrong( __FUNCTION__, __( 'Cheatin&#8217; huh?', 'wpas' ), '2.0' );
94
	}
95
96
	/**
97
	 * Disable unserializing of the class
98
	 *
99
	 * @since 2.0
100
	 * @return void
101
	 */
102
	public function __wakeup() {
103
		// Unserializing instances of the class is forbidden
104
		_doing_it_wrong( __FUNCTION__, __( 'Cheatin&#8217; huh?', 'wpas' ), '2.0' );
105
	}
106
107
	/**
108
	 * Setup MailChimp options
109
	 *
110
	 * @since 2.0
111
	 * @return void
112
	 */
113
	private function setup_options() {
114
		self::$api_key      = wpbo_get_option( 'mc_api_key', '' );
115
		self::$list_id      = wpbo_get_option( 'mc_list_id', '' );
116
		self::$double_optin = wpbo_get_option( 'mc_double_optin', true );
117
		self::$update       = wpbo_get_option( 'mc_update_existing', true );
118
		self::$welcome      = wpbo_get_option( 'mc_welcome', true );
119
		self::$fields       = apply_filters( 'wpbo_mc_merge_vars', array( 'FNAME' ) );
120
	}
121
122
	/**
123
	 * Load the MailChimp API wrapper
124
	 *
125
	 * @since 1.0
126
	 * @return void
127
	 */
128
	private function load_mailchimp_api_wrapper() {
129
		/**
130
		 * Load MailChimp API Wrapper
131
		 *
132
		 * @link https://bitbucket.org/mailchimp/mailchimp-api-php
133
		 */
134
		if ( ! class_exists( 'Drewm\MailChimp' ) ) {
135
			require( WPBO_PATH . 'vendor/drewm/mailchimp-api/src/Drewm/MailChimp.php' );
136
		}
137
	}
138
139
	/**
140
	 * Trigger form submission.
141
	 *
142
	 * Add a last couple of checks, set the redirects and
143
	 * finally subscribe the visitor to the MailChimp list.
144
	 *
145
	 * @since  1.0.0
146
	 *
147
	 * @param array $data Popup form data
148
	 *
149
	 * @return null
150
	 */
151
	public function submit( $data ) {
152
153
		/* Check for credentials */
154
		if ( empty( self::$api_key ) || empty( self::$list_id ) ) {
155
			return new WP_Error( 'missing_credentials', esc_html__( 'The MailChimp credentials are missing. Please verify your settings.', 'betteroptin' ) );
156
		}
157
158
		/* Do the subscription */
159
		$subscribe = $this->subscribe( $data );
160
161
		if ( isset( $subscribe['status'] ) && 'error' == $subscribe['status'] || false === $subscribe ) {
162
			return new WP_Error( 'missing_credentials', esc_html__( 'An error occurred during submission.', 'betteroptin' ) );
163
		}
164
165
		return true;
166
167
	}
168
169
170
	/**
171
	 * Check if MailChimp settings are correct.
172
	 *
173
	 * @since  1.0.0
174
	 * @return boolean True if MailChimp integration is ready to work
175
	 */
176
	public function is_mailchimp_ready() {
177
178
		if ( empty( self::$api_key ) || empty( self::$list_id ) ) {
179
			return false;
180
		} else {
181
			return true;
182
		}
183
184
	}
185
186
	/**
187
	 * Clean the post.
188
	 *
189
	 * Filter the post data and only keep
190
	 * values that are actually supported
191
	 * by the API.
192
	 *
193
	 * @since  1.0.0
194
	 * @return array Clean list of merge fields
195
	 */
196
	protected function clean_fields() {
197
198
		$fields = self::$fields;
199
		$clean  = array();
200
201
		/* Need to use a merge var for the name */
202
		if ( isset( $_POST['wpbo_name'] ) ) {
203
			$_POST['FNAME'] = $_POST['wpbo_name'];
204
		}
205
206
		foreach ( $fields as $field ) {
207
208
			if ( isset( $_POST[ $field ] ) ) {
209
				$clean[ $field ] = $_POST[ $field ];
210
			}
211
212
		}
213
214
		return $clean;
215
216
	}
217
218
	/**
219
	 * Subscribe the visitor to a list.
220
	 *
221
	 * @since  1.0.0
222
	 *
223
	 * @param array $data Popup form data
224
	 *
225
	 * @return array Result
226
	 */
227
	private function subscribe( $data ) {
228
229
		$popup_id    = (int) $data['wpbo_id'];
230
		$custom_list = get_post_meta( $popup_id, 'wpbo_mc_list', true );
231
		$list_id     = '' != $custom_list ? $custom_list : self::$list_id;
232
233
		// Prepare e-mail content
234
		$email = array(
235
			'email' => sanitize_email( $data['email'] ),
236
			'euid'  => md5( sanitize_email( $data['email'] ) ),
237
			'leid'  => false
238
		);
239
240
		// Get cleaned merge fields
241
		$merge_vars = $this->clean_fields();
242
243
		// MailChimp e-mail array
244
		$settings = array(
245
			'id'                => $list_id,
246
			'email'             => $email,
247
			'merge_vars'        => $merge_vars,
248
			'email_type'        => 'html',
249
			'double_optin'      => self::$double_optin,
250
			'update_existing'   => self::$update,
251
			'replace_interests' => false,
252
			'send_welcome'      => self::$welcome,
253
		);
254
255
		/* Instantiate the MailChimp API Wrapper */
256
		$mc = new \Drewm\MailChimp( self::$api_key );
257
258
		/**
259
		 * Get the groups.
260
		 */
261
		$groups = maybe_unserialize( get_post_meta( $popup_id, 'wpbo_mc_list_groups', true ) );
262
263
		if ( is_array( $groups ) ) {
264
265
			/* Declare the grouping array */
266
			if ( ! isset( $settings['merge_vars']['groupings'] ) ) {
267
				$settings['merge_vars']['groupings'] = array();
268
			}
269
270
			foreach ( $groups as $group => $option ) {
271
272
				if ( is_array( $option ) ) {
273
274
					$opts = array();
275
276
					foreach ( $option as $opt ) {
277
						array_push( $opts, $opt );
278
					}
279
280
					array_push( $settings['merge_vars']['groupings'], array( 'id' => $group, 'groups' => $opts ) );
281
282
				} else {
283
					array_push( $settings['merge_vars']['groupings'], array(
284
						'id'     => $group,
285
						'groups' => array( $option )
286
					) );
287
				}
288
289
			}
290
291
		}
292
293
		/* Call the API */
294
		$subscribe = $mc->call( 'lists/subscribe', $settings );
295
296
		return $subscribe;
297
298
	}
299
300
	/**
301
	 * Get user lists.
302
	 *
303
	 * @since  1.0.0
304
	 * @return array Array of available lists for this account
305
	 */
306
	public function get_lists() {
307
308
		if ( empty( self::$api_key ) ) {
309
			return array();
310
		}
311
312
		/* Instantiate */
313
		$mc = new \Drewm\MailChimp( self::$api_key );
314
315
		$lists = $mc->call( 'lists/list' );
316
317
		return $lists;
318
319
	}
320
321
	/**
322
	 * Get the groups list.
323
	 *
324
	 * @since  1.1.0
325
	 *
326
	 * @param  string $list_id ID of the list to get the groups of
327
	 *
328
	 * @return mixed            Array of groups or error
329
	 */
330
	public function get_groups( $list_id = '' ) {
331
332
		/* Verify the list ID and try to retrieve it if needed. */
333
		if ( empty( $list_id ) ) {
334
			return new WP_Error( 'list_id_missing', __( 'The list ID is missing.', 'wpmc' ) );
335
		}
336
337
		/* Try to get groups from cache */
338
		$groups = get_transient( "wpbo_mc_groups_list_$list_id" );
339
340
		if ( false !== $groups ) {
341
			return $groups;
342
		}
343
344
		/* Check if the credentials are set. */
345
		if ( empty( self::$api_key ) ) {
346
			return new WP_Error( 'api_credentials_missing', __( 'The API credentials are missing.', 'wpmc' ) );
347
		}
348
349
		/* Instanciate MailChimp API Wrapper. */
350
		$mc = new \Drewm\MailChimp( self::$api_key );
351
352
		/* Get the lists. */
353
		$groups = $mc->call( 'lists/interest-groupings', array(
354
				'id' => $list_id
355
			)
356
		);
357
358
		/* An error occurred during the request, thus no groups. */
359
		if ( isset( $groups['status'] ) && 'error' === $groups['status'] && isset( $groups['error'] ) ) {
360
			return new WP_Error( 'api_credentials_missing', $groups['error'] );
361
		} else {
362
363
			/* Set a transient to reduce load time */
364
			$lifetime = apply_filters( 'wpbo_mc_list_groups_cache_lifetime', 24 * 60 * 60 );
365
			set_transient( "wpbo_mc_groups_list_$list_id", $groups, $lifetime );
366
367
			/* Return the groups */
368
369
			return $groups;
370
371
		}
372
373
	}
374
375
	/**
376
	 * Check if a list has groups.
377
	 *
378
	 * Use the MailChimp API to check if a given mailing list
379
	 * has groups available.
380
	 *
381
	 * @since  1.1.0
382
	 *
383
	 * @param  string $list_id The list ID
384
	 *
385
	 * @return boolean          Request result
386
	 */
387
	public function has_groups( $list_id = '' ) {
388
389
		/* Verify the list ID and try to retrieve it if needed. */
390
		if ( empty( $list_id ) ) {
391
			return new WP_Error( 'list_id_missing', __( 'The list ID is missing.', 'wpmc' ) );
392
		}
393
394
		/* Get the groups. */
395
		$groups = $this->get_groups( $list_id );
396
397
		if ( is_wp_error( $groups ) || false === $groups || is_array( $groups ) && empty( $groups ) ) {
398
			return false;
399
		} else {
400
			return true;
401
		}
402
403
	}
404
405
}