diff --git a/includes/blocks/mailchimp/block.json b/includes/blocks/mailchimp/block.json index 0f2fe71..18705ee 100644 --- a/includes/blocks/mailchimp/block.json +++ b/includes/blocks/mailchimp/block.json @@ -3,7 +3,7 @@ "apiVersion": 2, "name": "mailchimp/mailchimp", "title": "Mailchimp List Subscribe Form", - "category": "text", + "category": "widgets", "description": "Mailchimp List Subscribe Form", "attributes": { "json": { @@ -32,11 +32,17 @@ }, "color": { "background": true, - "text": true - } + "text": true, + "border": true + }, + "typography": { + "fontSize": true, + "lineHeight": true, + "textAlign": true + } }, "textdomain": "mailchimp", "editorScript": "file:./index.js", "render": "file:./markup.php", "editorStyle": "file:./editor.css" -} \ No newline at end of file +} diff --git a/includes/blocks/mailchimp/class-mailchimp-list-subscribe-form-block.php b/includes/blocks/mailchimp/class-mailchimp-list-subscribe-form-block.php new file mode 100644 index 0000000..996dfb7 --- /dev/null +++ b/includes/blocks/mailchimp/class-mailchimp-list-subscribe-form-block.php @@ -0,0 +1,240 @@ + array( + 'header' => array( + 'type' => 'string', + 'default' => get_option( 'mc_header_content', '' ), + ), + 'sub_header' => array( + 'type' => 'string', + 'default' => get_option( 'mc_subheader_content', '' ), + ), + 'list_id' => array( + 'type' => 'string', + 'default' => get_option( 'mc_list_id', '' ), + ), + 'submit_text' => array( + 'type' => 'string', + 'default' => get_option( 'mc_submit_text', esc_html__( 'Subscribe', 'mailchimp' ) ), + ), + 'show_default_fields' => array( + 'type' => 'boolean', + 'default' => false, + ), + 'merge_fields_visibility' => array( + 'type' => 'object', + 'default' => $merge_fields_visibility, + ), + 'interest_groups_visibility' => array( + 'type' => 'object', + 'default' => $interest_groups_visibility, + ), + 'is_preview' => array( + 'type' => 'boolean', + 'default' => false, + ), + 'double_opt_in' => array( + 'type' => 'boolean', + 'default' => (bool) get_option( 'mc_double_optin', true ), + ), + 'update_existing_subscribers' => array( + 'type' => 'boolean', + 'default' => (bool) get_option( 'mc_update_existing', true ), + ), + 'show_unsubscribe_link' => array( + 'type' => 'boolean', + 'default' => (bool) get_option( 'mc_use_unsub_link', 'off' ) === 'on', + ), + 'unsubscribe_link_text' => array( + 'type' => 'string', + 'default' => esc_html__( 'unsubscribe from list', 'mailchimp' ), + ), + ), + ) + ); + } + + $data = array( + 'admin_settings_url' => esc_url_raw( admin_url( 'admin.php?page=mailchimp_sf_options' ) ), + 'lists' => $this->mailchimp_sf_get_lists(), + ); + $data = 'window.mailchimp_sf_block_data = ' . wp_json_encode( $data ); + wp_add_inline_script( 'mailchimp-mailchimp-editor-script', $data, 'before' ); + + ob_start(); + require_once MCSF_DIR . '/views/css/frontend.php'; + $data = ob_get_clean(); + wp_add_inline_style( 'mailchimp-mailchimp-editor-style', $data ); + } + + /** + * Get Mailchimp lists. + * + * @return array List of Mailchimp lists. + */ + public function mailchimp_sf_get_lists() { + // Just get out if nothing else matters... + $api = mailchimp_sf_get_api(); + if ( ! $api ) { + return array(); + } + + // we *could* support paging, but few users have that many lists (and shouldn't) + $lists = $api->get( 'lists', 100, array( 'fields' => 'lists.id,lists.name,lists.email_type_option' ) ); + if ( is_wp_error( $lists ) ) { + return array(); + } + return $lists['lists'] ?? array(); + } + + /** + * Register REST API endpoints. + */ + public function register_rest_endpoints() { + register_rest_route( + 'mailchimp/v1', + '/list-data/(?P[a-zA-Z0-9]+)/', + array( + 'methods' => WP_REST_Server::READABLE, + 'callback' => array( $this, 'get_list_data' ), + 'args' => array( + 'list_id' => array( + 'required' => true, + 'type' => 'string', + 'sanitize_callback' => 'sanitize_text_field', + 'description' => esc_html__( 'Mailchimp list ID to get data', 'mailchimp' ), + ), + ), + 'permission_callback' => array( $this, 'get_list_data_permissions_check' ), + ) + ); + } + + /** + * Get list data. + * + * @param WP_REST_Request $request Request object. + * @return WP_REST_Response|WP_Error + */ + public function get_list_data( $request ) { + $list_id = $request->get_param( 'list_id' ); + + $fields_key = 'mailchimp_sf_merge_fields_' . $list_id; + $merge_fields = get_option( $fields_key, array() ); + $groups_key = 'mailchimp_sf_interest_groups_' . $list_id; + $interest_groups = get_option( $groups_key, array() ); + + // If we don't have any merge fields, get them from the API. + if ( empty( $merge_fields ) ) { + $api = mailchimp_sf_get_api(); + $response = $api->get( 'lists/' . $list_id . '/merge-fields', 80 ); + + // if we get an error back from the api, return it. + if ( is_wp_error( $response ) ) { + return $response; + } + + $merge_fields = mailchimp_sf_add_email_field( $response['merge_fields'] ); + update_option( $fields_key, $merge_fields ); + } + + // If we don't have any interest groups, get them from the API. + if ( empty( $interest_groups ) ) { + $api = mailchimp_sf_get_api(); + $response = $api->get( 'lists/' . $list_id . '/interest-categories', 60 ); + + // if we get an error back from the api, return it. + if ( is_wp_error( $response ) ) { + return $response; + } + + if ( is_array( $response ) ) { + foreach ( $response['categories'] as $key => $ig ) { + $groups = $api->get( 'lists/' . $list_id . '/interest-categories/' . $ig['id'] . '/interests', 60 ); + $response['categories'][ $key ]['groups'] = $groups['interests']; + } + } + + $interest_groups = $response['categories']; + update_option( $groups_key, $interest_groups ); + } + + $data = array( + 'merge_fields' => $merge_fields, + 'interest_groups' => $interest_groups, + ); + + return rest_ensure_response( $data ); + } + + /** + * Check permissions for the list data. + * + * @return bool + */ + public function get_list_data_permissions_check() { + return current_user_can( 'edit_posts' ); + } +} diff --git a/includes/blocks/mailchimp/edit.js b/includes/blocks/mailchimp/edit.js index 3083d59..df4cba8 100644 --- a/includes/blocks/mailchimp/edit.js +++ b/includes/blocks/mailchimp/edit.js @@ -1,57 +1,218 @@ -import { useBlockProps } from '@wordpress/block-editor'; +import { RichText, InspectorControls, useBlockProps } from '@wordpress/block-editor'; import { __ } from '@wordpress/i18n'; -import { Placeholder, Button, Disabled } from '@wordpress/components'; +import { + PanelBody, + ToggleControl, + Disabled, + CheckboxControl, + SelectControl, +} from '@wordpress/components'; import ServerSideRender from '@wordpress/server-side-render'; -import { useSelect } from '@wordpress/data'; -import Icon from './icon'; +import { useEffect, useState } from '@wordpress/element'; +import apiFetch from '@wordpress/api-fetch'; -const disallowedThemesSSR = [ - 'twentytwentyone', - 'twentytwenty', - 'twentynineteen', - 'twentyeighteen', - 'twentyseventeen', - 'twentysixteen', - 'twentyfifteen', - 'twentyfourteen', -]; - -export const BlockEdit = ({ isSelected }) => { +export const BlockEdit = (props) => { + const { attributes, setAttributes } = props; + const { + header, + sub_header, + list_id, + submit_text, + show_default_fields, + double_opt_in, + update_existing_subscribers, + show_unsubscribe_link, + unsubscribe_link_text, + merge_fields_visibility, + interest_groups_visibility, + } = attributes; const blockProps = useBlockProps(); - const isDisallowedThemeSSR = useSelect((select) => { - const currentTheme = select('core').getCurrentTheme(); - if (!currentTheme || (!'template') in currentTheme) { - return false; - } - return disallowedThemesSSR.includes(currentTheme.template); - }); + + const { mailchimp_sf_block_data } = window; + const listOptions = + mailchimp_sf_block_data?.lists.map((list) => ({ + label: list.name, + value: list.id, + })) || []; + + const [listData, setListData] = useState({}); + + useEffect(() => { + // Fetch data from your API + apiFetch({ path: `/mailchimp/v1/list-data/${list_id}` }) + .then((data) => { + setListData(data); + }) + .catch((error) => { + // eslint-disable-next-line no-console + console.error('Error fetching list data:', error); + }); + }, [list_id]); return ( -
- {isSelected || isDisallowedThemeSSR ? ( - -
- -
-
- ) : ( + <> +
+ setAttributes({ header })} + /> + setAttributes({ sub_header })} + /> - + - )} -
+
+ setAttributes({ submit_text })} + /> +
+ {!!show_unsubscribe_link && ( + + )} +
+ + + + setAttributes({ list_id })} + help={__( + "Please select the Mailchimp list you'd like to connect to your form.", + 'mailchimp', + )} + __nextHasNoMarginBottom + /> +

{__('Form Fields', 'mailchimp')}

+ { + setAttributes({ show_default_fields }); + }} + help={__( + 'Show fields marked as visible in Mailchimp settings.', + 'mailchimp', + )} + __nextHasNoMarginBottom + /> + {!show_default_fields && + listData?.merge_fields?.map((field) => ( +
+ { + setAttributes({ + merge_fields_visibility: { + ...merge_fields_visibility, + [field.tag]: checked ? 'on' : 'off', + }, + }); + }} + className="mailchimp-merge-field-checkbox" + disabled={field.required} + __nextHasNoMarginBottom + /> +
+ ))} + {listData?.interest_groups?.length > 0 && ( +
+

{__('Groups Settings', 'mailchimp')}

+ {listData?.interest_groups?.map((group) => ( + { + setAttributes({ + interest_groups_visibility: { + ...interest_groups_visibility, + [group.id]: checked ? 'on' : 'off', + }, + }); + }} + className="mailchimp-group-checkbox" + __nextHasNoMarginBottom + /> + ))} +
+ )} +
+ + setAttributes({ double_opt_in: !double_opt_in })} + help={__( + "Before new your subscribers are added via the plugin, they'll need to confirm their email address.", + 'mailchimp', + )} + __nextHasNoMarginBottom + /> + + setAttributes({ + update_existing_subscribers: !update_existing_subscribers, + }) + } + help={__( + "If an existing subscriber fills out this form, we will update their information with what's provided.", + 'mailchimp', + )} + __nextHasNoMarginBottom + /> + + setAttributes({ show_unsubscribe_link: !show_unsubscribe_link }) + } + help={__( + "We'll automatically add a link to your list's unsubscribe form.", + 'mailchimp', + )} + __nextHasNoMarginBottom + /> + +
+ ); }; diff --git a/includes/blocks/mailchimp/editor.css b/includes/blocks/mailchimp/editor.css index 51a3281..01b14ca 100644 --- a/includes/blocks/mailchimp/editor.css +++ b/includes/blocks/mailchimp/editor.css @@ -2,3 +2,29 @@ #mc_message { display: none; } + +.mailchimp-merge-field-checkbox .components-base-control__field { + margin-bottom: 8px; +} + +.mailchimp-merge-field-checkbox input[type="checkbox"]:disabled { + opacity: 0.5; +} + +#mc_subheader { + line-height: 1.25em; + margin-bottom: 18px; +} + +#mc_signup_submit { + margin-top: 1.5em; + padding: 10px 8px; + width: 80%; +} +#mc_unsub_link a { + font-size: 0.75em; +} +#mc_unsub_link { + margin-top: 1.0em; + text-align: center; +} diff --git a/includes/blocks/mailchimp/markup.php b/includes/blocks/mailchimp/markup.php index 4ba6748..a4af1f7 100644 --- a/includes/blocks/mailchimp/markup.php +++ b/includes/blocks/mailchimp/markup.php @@ -8,6 +8,261 @@ ?>
> +
+
+ Settings and click Mailchimp Setup to try again.', + 'mailchimp' + ), + [ + 'strong' => [], + ] + ); + ?> +
+
+ + + +
+ +

+ +

+ +
+ +
+

+ +

+
+ +
+ + + +
+
+ +
+ + ' . mailchimp_form_field( $merge_field, $num_fields ) . '
'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Ignoring because form field is escaped in function + } else { + echo mailchimp_form_field( $merge_field, $num_fields, $should_display ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Ignoring because form field is escaped in function + } + } + + // Show an explanation of the * if there's more than one field + if ( $num_fields > 1 ) { + ?> +
+ * = +
+ +
+ +
+
+ + + +
+ +
+
    +
  • +
  • +
+
+
+ + + + + datacenter . '.list-manage.com'; + ?> + + +
+
+
+
diff --git a/mailchimp.php b/mailchimp.php index cb0fe0a..7f9fe9d 100644 --- a/mailchimp.php +++ b/mailchimp.php @@ -96,6 +96,11 @@ function () { $admin = new Mailchimp_Admin(); $admin->init(); +// Init the block. +require_once plugin_dir_path( __FILE__ ) . 'includes/blocks/mailchimp/class-mailchimp-list-subscribe-form-block.php'; +$block = new Mailchimp_List_Subscribe_Form_Block(); +$block->init(); + /** * Do the following plugin setup steps here * @@ -138,22 +143,20 @@ function mailchimp_sf_plugin_action_links( $links ) { */ function mailchimp_sf_load_resources() { // JS - if ( get_option( 'mc_use_javascript' ) === 'on' ) { - if ( ! is_admin() ) { - wp_enqueue_script( 'mailchimp_sf_main_js', MCSF_URL . 'assets/js/mailchimp.js', array( 'jquery', 'jquery-form' ), MCSF_VER, true ); - // some javascript to get ajax version submitting to the proper location - global $wp_scripts; - $wp_scripts->localize( - 'mailchimp_sf_main_js', - 'mailchimpSF', - array( - 'ajax_url' => trailingslashit( home_url() ), - ) - ); - } + if ( ! is_admin() ) { + wp_enqueue_script( 'mailchimp_sf_main_js', MCSF_URL . 'assets/js/mailchimp.js', array( 'jquery', 'jquery-form' ), MCSF_VER, true ); + // some javascript to get ajax version submitting to the proper location + global $wp_scripts; + $wp_scripts->localize( + 'mailchimp_sf_main_js', + 'mailchimpSF', + array( + 'ajax_url' => trailingslashit( home_url() ), + ) + ); } - if ( get_option( 'mc_use_datepicker' ) === 'on' && ! is_admin() ) { + if ( ! is_admin() ) { // Datepicker theme wp_enqueue_style( 'flick', MCSF_URL . 'assets/css/flick/flick.css', array(), MCSF_VER ); @@ -175,7 +178,7 @@ function mc_datepicker_load() { require_once MCSF_DIR . '/views/datepicker.php'; } -if ( get_option( 'mc_use_datepicker' ) === 'on' && ! is_admin() ) { +if ( ! is_admin() ) { add_action( 'wp_head', 'mc_datepicker_load' ); } @@ -374,8 +377,6 @@ function mailchimp_sf_needs_upgrade() { function mailchimp_sf_delete_setup() { $options = array( 'mc_user_id', - 'mc_use_javascript', - 'mc_use_datepicker', 'mc_use_unsub_link', 'mc_list_id', 'mc_list_name', @@ -436,9 +437,7 @@ function mailchimp_sf_set_form_defaults( $list_name = '' ) { update_option( 'mc_header_content', esc_html__( 'Sign up for', 'mailchimp' ) . ' ' . $list_name ); update_option( 'mc_submit_text', esc_html__( 'Subscribe', 'mailchimp' ) ); - update_option( 'mc_use_datepicker', 'on' ); update_option( 'mc_custom_style', 'off' ); - update_option( 'mc_use_javascript', 'on' ); update_option( 'mc_double_optin', true ); update_option( 'mc_use_unsub_link', 'off' ); update_option( 'mc_header_border_width', '1' ); @@ -459,27 +458,6 @@ function mailchimp_sf_set_form_defaults( $list_name = '' ) { **/ function mailchimp_sf_save_general_form_settings() { - // IF NOT DEV MODE - if ( isset( $_POST['mc_use_javascript'] ) ) { - update_option( 'mc_use_javascript', 'on' ); - $msg = '

' . esc_html__( 'Fancy Javascript submission turned On!', 'mailchimp' ) . '

'; - mailchimp_sf_global_msg( $msg ); - } elseif ( get_option( 'mc_use_javascript' ) !== 'off' ) { - update_option( 'mc_use_javascript', 'off' ); - $msg = '

' . esc_html__( 'Fancy Javascript submission turned Off!', 'mailchimp' ) . '

'; - mailchimp_sf_global_msg( $msg ); - } - - if ( isset( $_POST['mc_use_datepicker'] ) ) { - update_option( 'mc_use_datepicker', 'on' ); - $msg = '

' . esc_html__( 'Datepicker turned On!', 'mailchimp' ) . '

'; - mailchimp_sf_global_msg( $msg ); - } elseif ( get_option( 'mc_use_datepicker' ) !== 'off' ) { - update_option( 'mc_use_datepicker', 'off' ); - $msg = '

' . esc_html__( 'Datepicker turned Off!', 'mailchimp' ) . '

'; - mailchimp_sf_global_msg( $msg ); - } - /*Enable double optin toggle*/ if ( isset( $_POST['mc_double_optin'] ) ) { update_option( 'mc_double_optin', true ); @@ -778,38 +756,6 @@ function mailchimp_sf_shortcode() { } add_shortcode( 'mailchimpsf_form', 'mailchimp_sf_shortcode' ); -/** - * Add block - * - * @return void - */ -function mailchimp_sf_block() { - // In line with conditional register of the widget. - if ( ! mailchimp_sf_get_api() ) { - return; - } - - $blocks_dist_path = plugin_dir_path( __FILE__ ) . 'dist/blocks/'; - - if ( file_exists( $blocks_dist_path ) ) { - $block_json_files = glob( $blocks_dist_path . '*/block.json' ); - foreach ( $block_json_files as $filename ) { - $block_folder = dirname( $filename ); - register_block_type( $block_folder ); - } - } - - $data = 'window.MAILCHIMP_ADMIN_SETTINGS_URL = "' . esc_js( esc_url( admin_url( 'admin.php?page=mailchimp_sf_options' ) ) ) . '";'; - wp_add_inline_script( 'mailchimp-mailchimp-editor-script', $data, 'before' ); - - ob_start(); - require_once MCSF_DIR . '/views/css/frontend.php'; - $data = ob_get_clean(); - wp_add_inline_style( 'mailchimp-mailchimp-editor-style', $data ); -} - -add_action( 'init', 'mailchimp_sf_block' ); - /** * Attempts to signup a user, per the $_POST args. * diff --git a/mailchimp_widget.php b/mailchimp_widget.php index d2d129c..5e26fe8 100644 --- a/mailchimp_widget.php +++ b/mailchimp_widget.php @@ -366,15 +366,20 @@ function mailchimp_interest_group_field( $ig ) { /** * Generate and display markup for form fields * - * @param array $data Array containing informaoin about the field - * @param int $num_fields The number of fields total we'll be generating markup for. Used in calculating required text logic + * @param array $data Array containing informaoin about the field. + * @param int $num_fields The number of fields total we'll be generating markup for. Used in calculating required text logic. + * @param bool $should_display Whether or not the field should be displayed. * @return string */ -function mailchimp_form_field( $data, $num_fields ) { - $opt = 'mc_mv_' . $data['tag']; +function mailchimp_form_field( $data, $num_fields, $should_display = null ) { $html = ''; + $opt = 'mc_mv_' . $data['tag']; + if ( is_null( $should_display ) ) { + $should_display = get_option( $opt ) === 'on'; + } + // See if that var is set as required, or turned on (for display) - if ( $data['required'] || get_option( $opt ) === 'on' ) { + if ( $data['required'] || $should_display ) { $label = '