From 695701e8ac5bd57edfa7734f2c1522af4304a94e Mon Sep 17 00:00:00 2001 From: alaca Date: Tue, 30 Jun 2026 16:03:54 +0200 Subject: [PATCH 1/7] track: differentiate Mailchimp forms by form ID in analytics tracking --- assets/js/mailchimp.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/assets/js/mailchimp.js b/assets/js/mailchimp.js index b9a6d6ec..0dc85a95 100644 --- a/assets/js/mailchimp.js +++ b/assets/js/mailchimp.js @@ -121,12 +121,18 @@ for (let i = 0; i < forms.length; i++) { const listId = forms[i].getAttribute('data-list-id'); - if (listId && !tracked[listId]) { - tracked[listId] = true; + const formId = forms[i].getAttribute('data-form-id') || ''; + const key = `${listId}|${formId}`; + + if (listId && !tracked[key]) { + tracked[key] = true; const formData = new FormData(); formData.append('action', 'mailchimp_sf_track_form_view'); formData.append('list_id', listId); + if (formId) { + formData.append('form_id', formId); + } formData.append('mailchimp_sf_nonce', window.mailchimpSF.analytics_nonce); fetch(window.mailchimpSF.analytics_ajax_url, { From 075399b23e19afea3db9b7bd7020838ad95d6480 Mon Sep 17 00:00:00 2001 From: alaca Date: Tue, 30 Jun 2026 16:04:04 +0200 Subject: [PATCH 2/7] track: add form ID and title attributes for Mailchimp forms, enable forms registry and tracking --- includes/blocks/mailchimp/block.json | 8 +++++++ mailchimp.php | 5 ++++ mailchimp_upgrade.php | 19 +++++++++++++++ tests/cypress/e2e/block.test.js | 35 ++++++++++++++++++++++++++++ 4 files changed, 67 insertions(+) diff --git a/includes/blocks/mailchimp/block.json b/includes/blocks/mailchimp/block.json index c5049bed..dbb07679 100644 --- a/includes/blocks/mailchimp/block.json +++ b/includes/blocks/mailchimp/block.json @@ -6,6 +6,14 @@ "category": "widgets", "description": "Mailchimp List Subscribe Form", "attributes": { + "formId": { + "type": "string", + "default": "" + }, + "formTitle": { + "type": "string", + "default": "" + }, "list_id": { "type": "string" }, diff --git a/mailchimp.php b/mailchimp.php index 1ff709c4..fec64706 100644 --- a/mailchimp.php +++ b/mailchimp.php @@ -124,6 +124,11 @@ function () { $analytics_data = new Mailchimp_Analytics_Data(); $analytics_data->init(); +// Forms registry (form_id -> title) for per-form analytics labels. +require_once plugin_dir_path( __FILE__ ) . 'includes/class-mailchimp-forms-registry.php'; +$forms_registry = new Mailchimp_Forms_Registry(); +$forms_registry->init(); + // Subscriber activity (Mailchimp Activity API) data class. require_once plugin_dir_path( __FILE__ ) . 'includes/class-mailchimp-subscriber-activity.php'; $subscriber_activity = new Mailchimp_Subscriber_Activity(); diff --git a/mailchimp_upgrade.php b/mailchimp_upgrade.php index 4b2d41e8..2b99c7d9 100644 --- a/mailchimp_upgrade.php +++ b/mailchimp_upgrade.php @@ -50,6 +50,25 @@ function mailchimp_sf_maybe_create_analytics_table() { add_action( 'plugins_loaded', 'mailchimp_sf_maybe_create_analytics_table', 20 ); +/** + * Ensure the forms registry table exists and is at the current schema version. + * + * Runs independently of mailchimp_version_check(). + * + * @return void + */ +function mailchimp_sf_maybe_create_forms_table() { + if ( ! class_exists( 'Mailchimp_Forms_Registry' ) ) { + return; + } + if ( Mailchimp_Forms_Registry::DB_VERSION === get_option( 'mailchimp_sf_forms_db_version' ) ) { + return; + } + Mailchimp_Forms_Registry::create_table(); +} + +add_action( 'plugins_loaded', 'mailchimp_sf_maybe_create_forms_table', 20 ); + /** * Version 1.6.0 update routine * - Remove MonkeyRewards checkbox option diff --git a/tests/cypress/e2e/block.test.js b/tests/cypress/e2e/block.test.js index 6ba5f7ec..902a4f6b 100644 --- a/tests/cypress/e2e/block.test.js +++ b/tests/cypress/e2e/block.test.js @@ -40,6 +40,41 @@ describe('Block Tests', () => { }); }); + it('Block form has a stable analytics form ID wired through tracking', () => { + const uuid = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/; + + cy.intercept('POST', '**/admin-ajax.php').as('ajax'); + cy.visit(`/?p=${postId}`); + + // Rendered form carries a UUID data-form-id and a matching hidden input. + cy.get('.mc_signup_form') + .should('have.attr', 'data-form-id') + .and('match', uuid); + + cy.get('.mc_signup_form') + .invoke('attr', 'data-form-id') + .then((formId) => { + cy.get('input[name="mailchimp_sf_form_id"]').should('have.value', formId); + + // The view ping includes the form_id. + cy.wait('@ajax').then((interception) => { + expect(interception.request.body).to.include('mailchimp_sf_track_form_view'); + expect(interception.request.body).to.include(formId); + }); + + // The registry table has a row for this form. + cy.wpCli( + `wp db query "SELECT COUNT(*) FROM wp_mailchimp_sf_forms WHERE form_id = '${formId}'" --skip-column-names`, + ).then((res) => { + expect(res.stdout.trim()).to.eq('1'); + }); + + // The ID survives a reload (persisted in post content). + cy.reload(); + cy.get('.mc_signup_form').should('have.attr', 'data-form-id', formId); + }); + }); + it('Admin can set header and sub-header in block', () => { cy.visit(`/wp-admin/post.php?post=${postId}&action=edit`); From e95b1aaa577fa09331f878d74a7a1c7d97adbf8d Mon Sep 17 00:00:00 2001 From: alaca Date: Tue, 30 Jun 2026 16:04:22 +0200 Subject: [PATCH 3/7] track: add form title field and auto-generate form ID for Mailchimp block analytics --- includes/blocks/mailchimp/edit.js | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/includes/blocks/mailchimp/edit.js b/includes/blocks/mailchimp/edit.js index aaa97b87..f95c4ba1 100644 --- a/includes/blocks/mailchimp/edit.js +++ b/includes/blocks/mailchimp/edit.js @@ -10,6 +10,7 @@ import { PanelBody, ToggleControl, SelectControl, + TextControl, Spinner, Placeholder, } from '@wordpress/components'; @@ -61,8 +62,17 @@ export const BlockEdit = (props) => { show_required_indicator = true, required_indicator_text, template = 'default', + formTitle = '', } = attributes; + // Give every block instance a stable analytics ID. Generated once when + // empty and persisted with the post, so it survives edits and reordering. + useEffect(() => { + if (!attributes.formId && typeof window.crypto?.randomUUID === 'function') { + setAttributes({ formId: window.crypto.randomUUID() }); + } + }, []); // eslint-disable-line react-hooks/exhaustive-deps -- Only run on mount. + const [listData, setListData] = useState({}); const [isLoading, setIsLoading] = useState(true); const [error, setError] = useState(''); @@ -417,6 +427,20 @@ export const BlockEdit = (props) => { __nextHasNoMarginBottom /> + + setAttributes({ formTitle: value })} + help={__( + 'Used to identify this form in the Analytics dashboard. Defaults to the form header if left blank.', + 'mailchimp', + )} + __nextHasNoMarginBottom + /> + Date: Tue, 30 Jun 2026 16:05:04 +0200 Subject: [PATCH 4/7] track: add support for stable per-form analytics ID in Mailchimp block --- includes/blocks/mailchimp/markup.php | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/includes/blocks/mailchimp/markup.php b/includes/blocks/mailchimp/markup.php index 60e0ba14..73d89eb2 100644 --- a/includes/blocks/mailchimp/markup.php +++ b/includes/blocks/mailchimp/markup.php @@ -25,10 +25,14 @@ } // Make sure we have a list ID and it's valid. - $list_id = $attributes['list_id'] ?? ''; - $form_id = wp_unique_id( $list_id . '_' ); - $lists = ( new Mailchimp_List_Subscribe_Form_Blocks() )->get_lists(); - $list_ids = array_map( + $list_id = $attributes['list_id'] ?? ''; + $form_id = wp_unique_id( $list_id . '_' ); + + // Stable per-form analytics id from the block attribute. Empty for legacy + // blocks not yet re-saved + $mc_analytics_form_id = Mailchimp_Forms_Registry::sanitize_form_id( $attributes['formId'] ?? '' ); + $lists = ( new Mailchimp_List_Subscribe_Form_Blocks() )->get_lists(); + $list_ids = array_map( function ( $single_list ) { return $single_list['id']; }, @@ -105,8 +109,11 @@ function ( $single_list ) { } ?>
-