PluginProbe
Ebook Store / trunk
Ebook Store vtrunk
6.24 6.23 6.22 6.21 6.20 trunk
ebook-store / settings-MailChimp.php

settings-MailChimp.php in Ebook Store trunk, at settings-MailChimp.php

377 lines 17.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Ebook Store - Mailchimp settings tab.
4 *
5 * PHP 7.4 compatible.
6 *
7 * @package EbookStore
8 */
9
10 if ( ! defined( 'ABSPATH' ) ) {
11 exit;
12 }
13
14 settings_fields( 'ebook-settings-group-mailchimp' );
15 do_settings_sections( 'ebook-settings-group-mailchimp' );
16
17 $api_key = trim( (string) get_option( 'mailchimp_api_key', '' ) );
18 $selected_audience = (string) get_option( 'mailchimp_lists', '' );
19 $mailchimp_enabled = (string) get_option( 'mailchimp_integration_enabled', $selected_audience !== '' ? '1' : '' );
20
21 $has_api_key = ( $api_key !== '' );
22 $server_prefix = $has_api_key ? ebook_store_get_mailchimp_server_prefix( $api_key ) : '';
23 $key_looks_sane = ( $server_prefix !== '' );
24
25 // The audience lookup only runs when there is something to look up with. It is
26 // the same call the tab has always made on render; no new remote request.
27 $audiences = ( $has_api_key && $key_looks_sane ) ? ebook_store_get_mailchimp_lists() : false;
28
29 $audience_list = is_array( $audiences ) ? $audiences : array();
30 $audience_count = count( $audience_list );
31 $lookup_failed = ( $has_api_key && $key_looks_sane && ! is_array( $audiences ) );
32
33 // Every option registered in this tab's option group has to be submitted by the
34 // form. WordPress writes NULL over any registered option that is missing from
35 // the POST, so a control that is not rendered in the current state must be
36 // preserved by a hidden input or the saved value is silently wiped on save.
37 $rendered_audience_input = false;
38 $rendered_enabled_input = false;
39
40 $general_tab_url = function_exists( 'ebook_store_get_settings_tab_url' )
41 ? ebook_store_get_settings_tab_url( 'General' )
42 : admin_url( 'options-general.php?page=ebook_options.php' );
43
44 /**
45 * Hero status card: three plain-language lines about where this setup stands.
46 */
47 $mailchimp_status_card = function () use ( $has_api_key, $key_looks_sane, $lookup_failed, $audience_count, $selected_audience, $mailchimp_enabled ) {
48 if ( ! $has_api_key ) {
49 $key_state = 'muted';
50 $key_detail = __( 'No API key saved yet. That is the first step.', 'ebook-store' );
51 } elseif ( ! $key_looks_sane ) {
52 $key_state = 'error';
53 $key_detail = __( 'The saved key has no server suffix, so Mailchimp cannot be contacted.', 'ebook-store' );
54 } elseif ( $lookup_failed ) {
55 $key_state = 'error';
56 $key_detail = __( 'Mailchimp refused this key. Copy it again from your Mailchimp account.', 'ebook-store' );
57 } else {
58 $key_state = 'ok';
59 $key_detail = __( 'Saved and accepted by Mailchimp.', 'ebook-store' );
60 }
61
62 if ( ! $has_api_key || ! $key_looks_sane || $lookup_failed ) {
63 $list_state = 'muted';
64 $list_detail = __( 'Your audiences load once a working API key is saved.', 'ebook-store' );
65 } elseif ( $audience_count === 0 ) {
66 $list_state = 'warn';
67 $list_detail = __( 'This Mailchimp account has no audiences yet. Create one in Mailchimp first.', 'ebook-store' );
68 } else {
69 $list_state = 'ok';
70 $list_detail = sprintf(
71 /* translators: %s: number of Mailchimp audiences found, already formatted for the locale. */
72 _n( '%s audience found in this account.', '%s audiences found in this account.', $audience_count, 'ebook-store' ),
73 number_format_i18n( $audience_count )
74 );
75 }
76
77 if ( $mailchimp_enabled === '1' && $selected_audience !== '' ) {
78 $sync_state = 'ok';
79 $sync_detail = __( 'Buyers are added to the chosen audience after they pay.', 'ebook-store' );
80 } elseif ( $mailchimp_enabled === '1' ) {
81 $sync_state = 'warn';
82 $sync_detail = __( 'Switched on, but no audience is chosen, so nobody is being added.', 'ebook-store' );
83 } else {
84 $sync_state = 'muted';
85 $sync_detail = __( 'Switched off. Buyers are not added to Mailchimp.', 'ebook-store' );
86 }
87 ?>
88 <aside class="ebook-settings-status-card">
89 <h4><?php echo esc_html__( 'Current status', 'ebook-store' ); ?></h4>
90 <ul class="ebook-settings-status-list">
91 <?php
92 ebook_store_status_row( __( 'API key', 'ebook-store' ), $key_state, $key_detail );
93 ebook_store_status_row( __( 'Audiences', 'ebook-store' ), $list_state, $list_detail );
94 ebook_store_status_row( __( 'Adding buyers automatically', 'ebook-store' ), $sync_state, $sync_detail );
95 ?>
96 </ul>
97 </aside>
98 <?php
99 };
100
101 ebook_store_render_hero(
102 array(
103 'eyebrow' => __( 'Mailchimp', 'ebook-store' ),
104 'title' => __( 'Add your buyers to a Mailchimp audience', 'ebook-store' ),
105 'intro' => __( 'When someone pays for a book, Ebook Store can send their email address to one of your Mailchimp audiences, so you can keep in touch with your readers. Setting this up takes two steps: save your API key, then pick the audience.', 'ebook-store' ),
106 'aside' => $mailchimp_status_card,
107 )
108 );
109
110 ebook_store_pro_banner( __( 'Mailchimp', 'ebook-store' ) );
111
112 /* ---------------------------------------------------------------------------
113 * Step 1 - the API key. Always shown.
114 * ------------------------------------------------------------------------- */
115 ebook_store_section_open(
116 array(
117 'eyebrow' => __( 'Step 1', 'ebook-store' ),
118 'title' => __( 'Connect your Mailchimp account', 'ebook-store' ),
119 'intro' => __( 'The API key is the password that lets Ebook Store talk to your Mailchimp account. Use a key from the same Mailchimp account that holds the audience you want your buyers to join.', 'ebook-store' ),
120 'id' => 'ebook-mailchimp-connection',
121 'pro' => true,
122 )
123 );
124
125 ebook_store_steps(
126 __( 'Where to find your API key', 'ebook-store' ),
127 array(
128 __( 'Sign in to Mailchimp and open your account menu, then Account & billing.', 'ebook-store' ),
129 __( 'Go to Extras, then API keys.', 'ebook-store' ),
130 __( 'Choose Create A Key, give it a name such as “Ebook Store”, and copy the key it shows you.', 'ebook-store' ),
131 __( 'Paste the whole key into the box below and press Save Changes.', 'ebook-store' ),
132 )
133 );
134
135 ebook_store_field(
136 array(
137 'type' => 'text',
138 'name' => 'mailchimp_api_key',
139 'id' => 'mailchimp_api_key',
140 'label' => __( 'Mailchimp API key', 'ebook-store' ),
141 'value' => $api_key,
142 'placeholder' => 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-us21',
143 'mono' => true,
144 'wide' => true,
145 'pro' => true,
146 'help' => wp_kses_post(
147 sprintf(
148 /* translators: 1: example server suffix, e.g. -us21; 2: the letters "us" followed by two digits. */
149 __( 'Paste the key exactly as Mailchimp shows it, including the ending such as %1$s. That ending (%2$s) tells Ebook Store which Mailchimp server your account lives on, so a key without it will not work. If the key is wrong or was deleted in Mailchimp, buyers simply are not added to your audience; nothing else on your shop breaks.', 'ebook-store' ),
150 '<code>-us21</code>',
151 '<code>-usXX</code>'
152 )
153 ),
154 )
155 );
156
157 if ( ! $has_api_key ) {
158 ebook_store_callout(
159 __( 'Paste your API key above and press Save Changes. This page will then reload with the list of audiences from your Mailchimp account, and you can choose which one your buyers should join.', 'ebook-store' ),
160 'info',
161 __( 'Save your API key first:', 'ebook-store' )
162 );
163 } elseif ( ! $key_looks_sane ) {
164 ebook_store_callout(
165 wp_kses_post(
166 sprintf(
167 /* translators: %s: example server suffix, e.g. -us21. */
168 __( 'The key you saved has no server ending such as %s, so it is probably incomplete. Copy the whole key from Mailchimp again and save it once more.', 'ebook-store' ),
169 '<code>-us21</code>'
170 )
171 ),
172 'warning',
173 __( 'This key looks incomplete:', 'ebook-store' )
174 );
175 } elseif ( $lookup_failed ) {
176 ebook_store_callout(
177 __( 'Your key was saved, but Mailchimp did not accept it when we asked for your audiences. The key may have been deleted or revoked in Mailchimp, or your server may be blocked from reaching Mailchimp. Create a fresh key in Mailchimp and save it here.', 'ebook-store' ),
178 'warning',
179 __( 'Mailchimp did not answer with your audiences:', 'ebook-store' )
180 );
181 }
182
183 if ( ! ebook_store_has_pro_license() ) {
184 ebook_store_callout(
185 wp_kses_post(
186 sprintf(
187 /* translators: %s: link to the General settings tab. */
188 __( 'These boxes stay locked until a Pro license key is saved on the <a href="%s">General tab</a>.', 'ebook-store' ),
189 esc_url( $general_tab_url )
190 )
191 ),
192 'soft',
193 __( 'Pro feature:', 'ebook-store' )
194 );
195 }
196
197 ebook_store_section_close();
198
199 /* ---------------------------------------------------------------------------
200 * Step 2 - audience and switch. Only rendered once a key exists, so nobody is
201 * shown an empty dropdown that looks like "your account has no audiences".
202 * ------------------------------------------------------------------------- */
203 if ( $has_api_key ) {
204 ebook_store_section_open(
205 array(
206 'eyebrow' => __( 'Step 2', 'ebook-store' ),
207 'title' => __( 'Choose the audience and switch it on', 'ebook-store' ),
208 'intro' => __( 'Pick the Mailchimp audience your buyers should be added to, then turn the automatic adding on. Both are needed: an audience on its own does nothing until the switch is on.', 'ebook-store' ),
209 'id' => 'ebook-mailchimp-audience',
210 'pro' => true,
211 )
212 );
213
214 if ( $audience_count > 0 ) {
215 $audience_options = array(
216 '' => __( 'Do not add buyers to any audience', 'ebook-store' ),
217 );
218
219 foreach ( $audience_list as $audience ) {
220 $audience_id = isset( $audience->id ) ? (string) $audience->id : '';
221 if ( $audience_id === '' ) {
222 continue;
223 }
224 $audience_name = ( isset( $audience->name ) && $audience->name !== '' )
225 ? (string) $audience->name
226 : $audience_id;
227
228 $audience_options[ $audience_id ] = $audience_name;
229 }
230
231 // A previously chosen audience that no longer exists in Mailchimp would
232 // otherwise disappear silently and look like "nothing was selected".
233 $missing_selection = ( $selected_audience !== '' && ! isset( $audience_options[ $selected_audience ] ) );
234 if ( $missing_selection ) {
235 $audience_options[ $selected_audience ] = sprintf(
236 /* translators: %s: the saved Mailchimp audience id. */
237 __( 'Saved audience %s (no longer in this account)', 'ebook-store' ),
238 $selected_audience
239 );
240 }
241
242 ebook_store_field(
243 array(
244 'type' => 'select',
245 'name' => 'mailchimp_lists',
246 'id' => 'mailchimp_lists',
247 'label' => __( 'Audience buyers are added to', 'ebook-store' ),
248 'value' => $selected_audience,
249 'options' => $audience_options,
250 'wide' => true,
251 'pro' => true,
252 'help' => __( 'This list comes straight from your Mailchimp account. If you have just created a new audience in Mailchimp, save this page once and it will appear here.', 'ebook-store' ),
253 'note' => $missing_selection
254 ? __( 'The audience saved here was not returned by Mailchimp. It may have been deleted or renamed. Choose one of your current audiences instead.', 'ebook-store' )
255 : '',
256 'note_tone' => 'warning',
257 )
258 );
259
260 $rendered_audience_input = true;
261
262 ebook_store_toggle_grid_open();
263 ebook_store_toggle(
264 array(
265 'name' => 'mailchimp_integration_enabled',
266 'id' => 'mailchimp_integration_enabled',
267 'title' => __( 'Add buyers to Mailchimp after they pay', 'ebook-store' ),
268 'description' => __( 'Only paid orders are sent. Someone who is already in the audience is updated rather than added twice.', 'ebook-store' ),
269 'checked' => $mailchimp_enabled,
270 'pro' => true,
271 )
272 );
273 ebook_store_toggle_grid_close();
274
275 if ( $mailchimp_enabled === '1' && $selected_audience === '' ) {
276 ebook_store_callout(
277 __( 'Adding buyers is switched on, but no audience is chosen, so nothing is sent to Mailchimp. Pick an audience above and save.', 'ebook-store' ),
278 'warning',
279 __( 'One step missing:', 'ebook-store' )
280 );
281 }
282 } elseif ( $key_looks_sane && ! $lookup_failed ) {
283 ebook_store_callout(
284 __( 'Ebook Store reached your Mailchimp account, but there are no audiences in it yet. Create an audience in Mailchimp, then save this page again to pick it here.', 'ebook-store' ),
285 'warning',
286 __( 'No audiences in this account:', 'ebook-store' )
287 );
288
289 ebook_store_toggle_grid_open();
290 ebook_store_toggle(
291 array(
292 'name' => 'mailchimp_integration_enabled',
293 'id' => 'mailchimp_integration_enabled',
294 'title' => __( 'Add buyers to Mailchimp after they pay', 'ebook-store' ),
295 'description' => __( 'Nothing is sent until an audience exists and is chosen above.', 'ebook-store' ),
296 'checked' => $mailchimp_enabled,
297 'pro' => true,
298 )
299 );
300 ebook_store_toggle_grid_close();
301 } else {
302 ebook_store_callout(
303 __( 'Your audiences cannot be loaded until the API key above works, so there is nothing to choose yet. You can still switch the feature off here.', 'ebook-store' ),
304 'soft',
305 __( 'Waiting for a working API key:', 'ebook-store' )
306 );
307
308 ebook_store_toggle_grid_open();
309 ebook_store_toggle(
310 array(
311 'name' => 'mailchimp_integration_enabled',
312 'id' => 'mailchimp_integration_enabled',
313 'title' => __( 'Add buyers to Mailchimp after they pay', 'ebook-store' ),
314 'description' => __( 'Leave this off while the API key is not working.', 'ebook-store' ),
315 'checked' => $mailchimp_enabled,
316 'pro' => true,
317 )
318 );
319 ebook_store_toggle_grid_close();
320 }
321
322 // All three branches above render the enable toggle, and that helper emits
323 // its own paired hidden input for the unchecked state.
324 $rendered_enabled_input = true;
325
326 ebook_store_section_close();
327 }
328
329 /* ---------------------------------------------------------------------------
330 * Keep the settings this tab owns but did not draw a control for.
331 *
332 * Without a working API key there is no audience dropdown and no toggle; with a
333 * key that returns no audiences there is no dropdown. Those options still
334 * belong to this option group, so they have to be posted back unchanged or
335 * WordPress blanks them, quietly switching the integration off and losing the
336 * chosen audience.
337 * ------------------------------------------------------------------------- */
338 if ( ! $rendered_audience_input || ! $rendered_enabled_input ) {
339 ?>
340 <div class="ebook-settings-preserved-values" hidden="hidden">
341 <?php if ( ! $rendered_audience_input ) { ?>
342 <input type="hidden" name="mailchimp_lists" value="<?php echo esc_attr( $selected_audience ); ?>" />
343 <?php } ?>
344 <?php if ( ! $rendered_enabled_input ) { ?>
345 <input type="hidden" name="mailchimp_integration_enabled" value="<?php echo esc_attr( $mailchimp_enabled === '1' ? '1' : '' ); ?>" />
346 <?php } ?>
347 </div>
348 <?php
349 }
350
351 /* ---------------------------------------------------------------------------
352 * What to expect, in plain words.
353 * ------------------------------------------------------------------------- */
354 ebook_store_section_open(
355 array(
356 'eyebrow' => __( 'Good to know', 'ebook-store' ),
357 'title' => __( 'What happens after a sale', 'ebook-store' ),
358 'intro' => __( 'A short summary of how Ebook Store behaves once this is connected.', 'ebook-store' ),
359 'id' => 'ebook-mailchimp-behaviour',
360 )
361 );
362 ?>
363 <ul class="ebook-settings-checklist">
364 <li><?php echo esc_html__( 'Buyers are only sent to Mailchimp when the switch is on and an audience is chosen.', 'ebook-store' ); ?></li>
365 <li><?php echo esc_html__( 'Only the email address from a completed, paid order is sent.', 'ebook-store' ); ?></li>
366 <li><?php echo esc_html__( 'Someone who is already in the audience is updated, not added a second time.', 'ebook-store' ); ?></li>
367 <li><?php echo esc_html__( 'If Mailchimp is unreachable, the sale and the download still go through as normal.', 'ebook-store' ); ?></li>
368 <li><?php echo esc_html__( 'No special hosting option such as allow_url_fopen is needed for this to work.', 'ebook-store' ); ?></li>
369 </ul>
370 <?php
371 ebook_store_callout(
372 __( 'Mailchimp expects people to have agreed to hear from you. Say on your checkout or book page that buyers will be added to your mailing list.', 'ebook-store' ),
373 'soft',
374 __( 'Consent:', 'ebook-store' )
375 );
376 ebook_store_section_close();
377