Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
136 changes: 136 additions & 0 deletions assets/css/analytics.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
/**
* Mailchimp Analytics Page Styles
*
* @package Mailchimp
*/

/* Filters bar */
.mailchimp-sf-analytics-wrapper {
max-width: 1200px;
margin: 20px 0;
}

.mailchimp-sf-analytics-filters {
display: flex;
flex-wrap: wrap;
align-items: flex-end;
gap: 16px;
padding: 20px;
background: #fff;
border: 1px solid #dcdcde;
border-radius: 4px;
margin-bottom: 20px;
}

.mailchimp-sf-analytics-filter-group {
display: flex;
flex-direction: column;
gap: 4px;
}

.mailchimp-sf-analytics-filter-group label {
font-size: 12px;
font-weight: 600;
color: #1d2327;
text-transform: uppercase;
letter-spacing: 0.5px;
}

.mailchimp-sf-analytics-filter-group select,
.mailchimp-sf-analytics-filter-group input[type="date"] {
min-width: 180px;
height: 36px;
padding: 0 8px;
border: 1px solid #8c8f94;
border-radius: 4px;
font-size: 14px;
color: #1d2327;
background-color: #fff;
}

.mailchimp-sf-analytics-filter-group select:focus,
.mailchimp-sf-analytics-filter-group input[type="date"]:focus {
border-color: #007cba;
box-shadow: 0 0 0 1px #007cba;
outline: none;
}

/* Custom date range row */
.mailchimp-sf-custom-dates {
flex-direction: row;
align-items: flex-end;
gap: 8px;
}

.mailchimp-sf-custom-dates label {
align-self: center;
}

/* Resolved date range display */
.mailchimp-sf-analytics-date-display {
margin-left: auto;
align-self: center;
font-size: 14px;
color: #50575e;
font-style: italic;
}

/* Content area */
.mailchimp-sf-analytics-content {
padding: 24px;
background: #fff;
border: 1px solid #dcdcde;
border-radius: 4px;
min-height: 200px;
margin-bottom: 20px;
}

.mailchimp-sf-analytics-placeholder {
display: flex;
align-items: center;
justify-content: center;
min-height: 200px;
color: #8c8f94;
font-size: 15px;
}

/* Deep link */
.mailchimp-sf-analytics-deep-link {
margin-top: 16px;
}

.mailchimp-sf-analytics-deep-link a {
display: inline-flex;
align-items: center;
gap: 6px;
}

.mailchimp-sf-analytics-deep-link .dashicons {
font-size: 16px;
width: 16px;
height: 16px;
line-height: 16px;
}

/* Responsive */
@media screen and (max-width: 782px) {
.mailchimp-sf-analytics-filters {
flex-direction: column;
align-items: stretch;
}

.mailchimp-sf-analytics-date-display {
margin-left: 0;
}

.mailchimp-sf-custom-dates {
flex-direction: column;
align-items: stretch;
}

.mailchimp-sf-analytics-filter-group select,
.mailchimp-sf-analytics-filter-group input[type="date"] {
min-width: auto;
width: 100%;
}
}
121 changes: 121 additions & 0 deletions assets/js/analytics.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
/**
* Mailchimp Analytics Page JavaScript
*
* @package Mailchimp
*/

(function () {
const dateRangeSelect = document.getElementById('mailchimp-sf-date-range');
const customDates = document.querySelector('.mailchimp-sf-custom-dates');
const dateFrom = document.getElementById('mailchimp-sf-date-from');
const dateTo = document.getElementById('mailchimp-sf-date-to');
const listFilter = document.getElementById('mailchimp-sf-list-filter');
const resolvedDisplay = document.getElementById('mailchimp-sf-resolved-date-range');

/**
* Format a Date object to a human-readable string.
*
* @param {Date} date Date to format.
* @returns {string} Formatted date string.
*/
function formatDate(date) {
return date.toLocaleDateString(undefined, {
year: 'numeric',
month: 'short',
day: 'numeric',
});
}

/**
* Get the resolved date range based on current filter selection.
*
* @returns {{ from: Date, to: Date }|null} Date range or null.
*/
function getDateRange() {
const { value } = dateRangeSelect;
let to = new Date();
let from;

if (value === 'custom') {
if (!dateFrom.value || !dateTo.value) {
return null;
}
from = new Date(`${dateFrom.value}T00:00:00`);
to = new Date(`${dateTo.value}T23:59:59`);
Copy link

Copilot AI Mar 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getDateRange() does not validate that the custom "From" date is <= the "To" date. As written, selecting an inverted range will still dispatch a refresh event with a nonsensical window. Add a check (and either swap the values or block refresh with a user-visible message) before returning the range.

Suggested change
to = new Date(`${dateTo.value}T23:59:59`);
to = new Date(`${dateTo.value}T23:59:59`);
if (from > to) {
const temp = from;
from = to;
to = temp;
}

Copilot uses AI. Check for mistakes.
return { from, to };
}

const days = parseInt(value, 10);
from = new Date();
from.setDate(from.getDate() - days);
return { from, to };
}

/**
* Update the resolved date range display text.
*/
function updateResolvedDateRange() {
const range = getDateRange();
if (range) {
resolvedDisplay.textContent = `${formatDate(range.from)} \u2013 ${formatDate(range.to)}`;
} else {
resolvedDisplay.textContent = '';
}
}

/**
* Toggle visibility of custom date inputs.
*/
function toggleCustomDates() {
const isCustom = dateRangeSelect.value === 'custom';
customDates.style.display = isCustom ? 'flex' : 'none';
}
Comment on lines +69 to +72
Copy link

Copilot AI Mar 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

toggleCustomDates() assumes .mailchimp-sf-custom-dates exists; if it’s missing for any reason, customDates will be null and customDates.style will throw, breaking the page JS. Add a null guard for customDates (and/or for dateRangeSelect) before accessing .style to make the script resilient.

Copilot uses AI. Check for mistakes.

/**
* Refresh analytics sections when filters change.
*/
function refreshAnalytics() {
updateResolvedDateRange();

const range = getDateRange();
const listId = listFilter ? listFilter.value : '';

if (!range) {
return;
}

// Dispatch a custom event so other scripts can listen for filter changes.
const event = new CustomEvent('mailchimp-analytics-refresh', {
detail: {
from: range.from.toISOString(),
to: range.to.toISOString(),
listId,
},
Comment on lines +87 to +93
Copy link

Copilot AI Mar 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The refresh event converts the selected dates to toISOString(), which shifts the timestamp into UTC and can change the calendar day relative to the user-selected local date (e.g., local midnight becomes the previous day in UTC for positive offsets). If downstream code/API expects date-boundaries matching the picker values, prefer emitting the original YYYY-MM-DD strings (or construct UTC dates explicitly) instead of ISO strings derived from local Date objects.

Copilot uses AI. Check for mistakes.
});
document.dispatchEvent(event);
}

// Bind events.
if (dateRangeSelect) {
dateRangeSelect.addEventListener('change', function () {
toggleCustomDates();
refreshAnalytics();
});
}

if (dateFrom) {
dateFrom.addEventListener('change', refreshAnalytics);
}

if (dateTo) {
dateTo.addEventListener('change', refreshAnalytics);
}

if (listFilter) {
listFilter.addEventListener('change', refreshAnalytics);
}

// Initialize on load.
toggleCustomDates();
updateResolvedDateRange();
})();
89 changes: 89 additions & 0 deletions includes/admin/templates/analytics.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
<?php
/**
* Analytics page template
*
* @package Mailchimp
*/

$user = get_option( 'mc_user' );
$is_logged_in = ! ( ! $user || ( ! get_option( 'mc_api_key' ) && ! mailchimp_sf_get_access_token() ) );
Comment on lines +8 to +9
Copy link

Copilot AI Mar 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This template computes $user and $is_logged_in but never uses them. Please remove the unused variables (or use $is_logged_in to gate the page content) to avoid dead code and keep the template consistent with the rest of the admin templates.

Suggested change
$user = get_option( 'mc_user' );
$is_logged_in = ! ( ! $user || ( ! get_option( 'mc_api_key' ) && ! mailchimp_sf_get_access_token() ) );

Copilot uses AI. Check for mistakes.
$lists = get_option( 'mailchimp_sf_lists', array() );
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Better to use existing function. Something like:

$lists    = ( new Mailchimp_List_Subscribe_Form_Blocks() )->get_lists();

Though we should move get_lists() to utils, but it’s fine not to handle that in this PR.

$current_list = get_option( 'mc_list_id', '' );
$dc = get_option( 'mc_datacenter', '' );
?>
<div id="mailchimp-sf-analytics-page">
<?php require_once MCSF_DIR . 'includes/admin/templates/header.php'; ?>
Copy link

Copilot AI Mar 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Other admin templates include the shared header via include_once ... // phpcs:ignore PEAR.Files.IncludingFile.UseRequireOnce. Using require_once here without the suppression is likely to trip PHPCS in this repo and is inconsistent with the existing pattern. Please switch to the same include_once + PHPCS ignore comment used in settings.php/create-account-page.php.

Suggested change
<?php require_once MCSF_DIR . 'includes/admin/templates/header.php'; ?>
<?php include_once MCSF_DIR . 'includes/admin/templates/header.php'; // phpcs:ignore PEAR.Files.IncludingFile.UseRequireOnce ?>

Copilot uses AI. Check for mistakes.

<div class="mailchimp-sf-settings-page-hero-wrapper">
<div class="mailchimp-sf-settings-page-hero">
<div class="mailchimp-sf-settings-page-hero-title-wrapper">
<h1 class="mailchimp-sf-settings-page-hero-title">
<?php esc_html_e( 'Analytics', 'mailchimp' ); ?>
</h1>
<p class="mailchimp-sf-settings-page-hero-description">
<?php esc_html_e( 'View audience analytics and insights for your Mailchimp lists.', 'mailchimp' ); ?>
</p>
</div>
</div>
</div>

<div class="wrap">
<div class="mailchimp-sf-analytics-wrapper">
<div class="mailchimp-sf-analytics-filters">
<div class="mailchimp-sf-analytics-filter-group">
<label for="mailchimp-sf-date-range"><?php esc_html_e( 'Date Range', 'mailchimp' ); ?></label>
<select id="mailchimp-sf-date-range">
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we make the date range similar to what we have in the Figma design? It doesn’t need to be exact/pixel-perfect, but we should align the UI with what we have on the Mailchimp side. Fine to handle this in follow up PR if you want.
https://admin.mailchimp.com/analytics/audience-analytics

Image

<option value="7"><?php esc_html_e( 'Last 7 days', 'mailchimp' ); ?></option>
<option value="30" selected><?php esc_html_e( 'Last 30 days', 'mailchimp' ); ?></option>
<option value="90"><?php esc_html_e( 'Last 90 days', 'mailchimp' ); ?></option>
<option value="180"><?php esc_html_e( 'Last 6 months', 'mailchimp' ); ?></option>
<option value="365"><?php esc_html_e( 'Last year', 'mailchimp' ); ?></option>
<option value="custom"><?php esc_html_e( 'Custom', 'mailchimp' ); ?></option>
</select>
</div>

<div class="mailchimp-sf-analytics-filter-group mailchimp-sf-custom-dates" style="display: none;">
<label for="mailchimp-sf-date-from"><?php esc_html_e( 'From', 'mailchimp' ); ?></label>
<input type="date" id="mailchimp-sf-date-from" />
<label for="mailchimp-sf-date-to"><?php esc_html_e( 'To', 'mailchimp' ); ?></label>
<input type="date" id="mailchimp-sf-date-to" />
</div>

<div class="mailchimp-sf-analytics-filter-group">
<label for="mailchimp-sf-list-filter"><?php esc_html_e( 'List', 'mailchimp' ); ?></label>
<select id="mailchimp-sf-list-filter">
<?php if ( ! empty( $lists ) ) : ?>
<?php foreach ( $lists as $list ) : ?>
<option value="<?php echo esc_attr( $list['id'] ); ?>" <?php selected( $list['id'], $current_list ); ?>>
<?php echo esc_html( $list['name'] ); ?>
</option>
<?php endforeach; ?>
<?php endif; ?>
</select>
</div>

<div class="mailchimp-sf-analytics-date-display">
<span id="mailchimp-sf-resolved-date-range"></span>
</div>
</div>

<div class="mailchimp-sf-analytics-content" id="mailchimp-sf-analytics-content">
<div class="mailchimp-sf-analytics-placeholder">
<p><?php esc_html_e( 'Select a date range and list to view analytics.', 'mailchimp' ); ?></p>
</div>
</div>

<?php if ( $dc ) : ?>
<div class="mailchimp-sf-analytics-deep-link">
<a href="<?php echo esc_url( 'https://' . $dc . '.admin.mailchimp.com/analytics/audience-analytics/' ); ?>"
target="_blank"
rel="noopener noreferrer"
class="mailchimp-sf-button btn-secondary">
<?php esc_html_e( 'View detailed analytics in Mailchimp', 'mailchimp' ); ?>
<span class="dashicons dashicons-external" aria-hidden="true"></span>
</a>
</div>
<?php endif; ?>
</div>
</div>
</div>
10 changes: 10 additions & 0 deletions includes/class-mailchimp-admin.php
Original file line number Diff line number Diff line change
Expand Up @@ -581,6 +581,16 @@ public function add_admin_menu_pages() {
'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA1Mi4wMyA1NSI+PGRlZnM+PHN0eWxlPi5jbHMtMXtmaWxsOiNmZmY7fTwvc3R5bGU+PC9kZWZzPjx0aXRsZT5Bc3NldCAxPC90aXRsZT48ZyBpZD0iTGF5ZXJfMiIgZGF0YS1uYW1lPSJMYXllciAyIj48ZyBpZD0iTGF5ZXJfMS0yIiBkYXRhLW5hbWU9IkxheWVyIDEiPjxwYXRoIGNsYXNzPSJjbHMtMSIgZD0iTTExLjY0LDI4LjU0YTQuNzUsNC43NSwwLDAsMC0xLjE3LjA4Yy0yLjc5LjU2LTQuMzYsMi45NC00LjA1LDZhNi4yNCw2LjI0LDAsMCwwLDUuNzIsNS4yMSw0LjE3LDQuMTcsMCwwLDAsLjgtLjA2YzIuODMtLjQ4LDMuNTctMy41NSwzLjEtNi41N0MxNS41MSwyOS44MywxMy4yMSwyOC42MywxMS42NCwyOC41NFptMi43Nyw4LjA3YTEuMTcsMS4xNywwLDAsMS0xLjEuNTUsMS41MywxLjUzLDAsMCwxLTEuMzctMS41OEE0LDQsMCwwLDEsMTIuMjMsMzRhMS40NCwxLjQ0LDAsMCwwLS41NS0xLjc0LDEuNDgsMS40OCwwLDAsMC0xLjEyLS4yMSwxLjQ0LDEuNDQsMCwwLDAtLjkyLjY0LDMuMzksMy4zOSwwLDAsMC0uMzQuNzlsMCwuMTFjLS4xMy4zNC0uMzMuNDUtLjQ3LjQzcy0uMTYtLjA1LS4yMS0uMjFhMywzLDAsMCwxLC43OC0yLjU1LDIuNDYsMi40NiwwLDAsMSwyLjExLS43NiwyLjUsMi41LDAsMCwxLDEuOTEsMS4zOSwzLjE5LDMuMTksMCwwLDEtLjIzLDIuODJsLS4wOS4yQTEuMTYsMS4xNiwwLDAsMCwxMywzNmEuNzQuNzQsMCwwLDAsLjYzLjMyLDEuMzgsMS4zOCwwLDAsMCwuMzQsMGMuMTUsMCwuMy0uMDcuMzksMEEuMjQuMjQsMCwwLDEsMTQuNDEsMzYuNjFaIi8+PHBhdGggY2xhc3M9ImNscy0xIiBkPSJNNTEsMzMuODhhMy44NCwzLjg0LDAsMCwwLTEuMTUtMWwtLjExLS4zNy0uMTQtLjQyYTUuNTcsNS41NywwLDAsMCwuNS0zLjMyLDUuNDMsNS40MywwLDAsMC0xLjU0LTMsMTAuMDksMTAuMDksMCwwLDAtNC4yNC0yLjI2YzAtLjY3LDAtMS40My0uMDYtMS45YTEyLjgzLDEyLjgzLDAsMCwwLS40OS0zLjI1LDEwLjQ2LDEwLjQ2LDAsMCwwLTEuMy0yLjkyYzIuMTQtMi41NiwzLjI5LTUuMjEsMy4yOS03LjU3LDAtMy44My0zLTYuMy03LjU5LTYuM2ExOS4zLDE5LjMsMCwwLDAtNy4yMiwxLjZsLS4zNC4xNEwyOC43LDEuNTJBNi4zMSw2LjMxLDAsMCwwLDI0LjQzLDAsMTQuMDcsMTQuMDcsMCwwLDAsMTcuNiwyLjJhMzYuOTMsMzYuOTMsMCwwLDAtNi43OCw1LjIxYy00LjYsNC4zOC04LjMsOS42My05LjkxLDE0QTEyLjUxLDEyLjUxLDAsMCwwLDAsMjYuNTRhNi4xNiw2LjE2LDAsMCwwLDIuMTMsNC40bC43OC42NkExMC40NCwxMC40NCwwLDAsMCwyLjc0LDM1YTkuMzYsOS4zNiwwLDAsMCwzLjIxLDYsMTAsMTAsMCwwLDAsNS4xMywyLjQzLDIwLjE5LDIwLjE5LDAsMCwwLDcuMzEsOEEyMy4zMywyMy4zMywwLDAsMCwzMC4xNyw1NUgzMWEyMy4yNywyMy4yNywwLDAsMCwxMi0zLjE2LDE5LjEsMTkuMSwwLDAsMCw3LjgyLTkuMDZsMCwwQTE2Ljg5LDE2Ljg5LDAsMCwwLDUyLDM3LjIzLDUuMTcsNS4xNywwLDAsMCw1MSwzMy44OFptLTEuNzgsOC4yMWMtMyw3LjI5LTEwLjMsMTEuMzUtMTksMTEuMDktOC4wNi0uMjQtMTQuOTQtNC41LTE4LTExLjQzYTcuOTQsNy45NCwwLDAsMS01LjEyLTIuMDYsNy41Niw3LjU2LDAsMCwxLTIuNjEtNC44NUE4LjMxLDguMzEsMCwwLDEsNSwzMUwzLjMyLDI5LjU2Qy00LjQyLDIzLDE5Ljc3LTMuODYsMjcuNTEsMi44OWwyLjY0LDIuNTgsMS40NC0uNjFjNi43OS0yLjgxLDEyLjMtMS40NSwxMi4zLDMsMCwyLjMzLTEuNDgsNS4wNS0zLjg2LDcuNTJhNy41NCw3LjU0LDAsMCwxLDIsMy40OCwxMSwxMSwwLDAsMSwuNDIsMi44MmMwLDEsLjA5LDMuMTYuMDksMy4ybDEsLjI3QTguNjQsOC42NCwwLDAsMSw0Ny4yLDI3YTMuNjYsMy42NiwwLDAsMSwxLjA2LDIuMDZBNCw0LDAsMCwxLDQ3LjU1LDMyLDEwLjE1LDEwLjE1LDAsMCwxLDQ4LDMzLjA4Yy4yLjY0LjM1LDEuMTguMzcsMS4yNS43NCwwLDEuODkuODUsMS44OSwyLjg5QTE1LjI5LDE1LjI5LDAsMCwxLDQ5LjE4LDQyLjA5WiIvPjxwYXRoIGNsYXNzPSJjbHMtMSIgZD0iTTQ4LDM2YTEuMzYsMS4zNiwwLDAsMC0uODYtLjE2LDExLjc2LDExLjc2LDAsMCwwLS44Mi0yLjc4QTE3Ljg5LDE3Ljg5LDAsMCwxLDQwLjQ1LDM2YTIzLjY0LDIzLjY0LDAsMCwxLTcuODEuODRjLTEuNjktLjE0LTIuODEtLjYzLTMuMjMuNzRhMTguMywxOC4zLDAsMCwwLDgsLjgxLjE0LjE0LDAsMCwxLC4xNi4xMy4xNS4xNSwwLDAsMS0uMDkuMTVzLTMuMTQsMS40Ni04LjE0LS4wOGEyLjU4LDIuNTgsMCwwLDAsMS44MywxLjkxLDguMjQsOC4yNCwwLDAsMCwxLjQ0LjM5YzYuMTksMS4wNiwxMi0yLjQ3LDEzLjI3LTMuMzYuMS0uMDcuMTYsMCwuMDguMTJsLS4xMy4xOGMtMS41OSwyLjA2LTUuODgsNC40NC0xMS40NSw0LjQ0LTIuNDMsMC00Ljg2LS44Ni01Ljc1LTIuMTctMS4zOC0yLS4wNy01LDIuMjQtNC43MWwxLC4xMWEyMS4xMywyMS4xMywwLDAsMCwxMC41LTEuNjhjMy4xNS0xLjQ2LDQuMzQtMy4wNyw0LjE2LTQuMzdBMS44NywxLjg3LDAsMCwwLDQ2LDI4LjM0YTYuOCw2LjgsMCwwLDAtMy0xLjQxYy0uNS0uMTQtLjg0LS4yMy0xLjItLjM1LS42NS0uMjEtMS0uMzktMS0xLjYxLDAtLjUzLS4xMi0yLjQtLjE2LTMuMTYtLjA2LTEuMzUtLjIyLTMuMTktMS4zNi00YTEuOTIsMS45MiwwLDAsMC0xLS4zMSwxLjg2LDEuODYsMCwwLDAtLjU4LjA2LDMuMDcsMy4wNywwLDAsMC0xLjUyLjg2LDUuMjQsNS4yNCwwLDAsMS00LDEuMzJjLS44LDAtMS42NS0uMTYtMi42Mi0uMjJsLS41NywwYTUuMjIsNS4yMiwwLDAsMC01LDQuNTdjLS41NiwzLjgzLDIuMjIsNS44MSwzLDdhMSwxLDAsMCwxLC4yMi41Mi44My44MywwLDAsMS0uMjguNTVoMGE5LjgsOS44LDAsMCwwLTIuMTYsOS4yLDcuNTksNy41OSwwLDAsMCwuNDEsMS4xMmMyLDQuNzMsOC4zLDYuOTMsMTQuNDMsNC45M2ExNS4wNiwxNS4wNiwwLDAsMCwyLjMzLTEsMTIuMjMsMTIuMjMsMCwwLDAsMy41Ny0yLjY3LDEwLjYxLDEwLjYxLDAsMCwwLDMtNS44MkM0OC42LDM2LjcsNDguMzMsMzYuMjMsNDgsMzZabS04LjI1LTcuODJjMCwuNS0uMzEuOTEtLjY4LjlzLS42Ni0uNDItLjY1LS45Mi4zMS0uOTEuNjgtLjlTMzkuNzIsMjcuNjgsMzkuNzEsMjguMThabS0xLjY4LTZjLjcxLS4xMiwxLjA2LjYyLDEuMzIsMS44NWEzLjY0LDMuNjQsMCwwLDEtLjA1LDIsNC4xNCw0LjE0LDAsMCwwLTEuMDYsMCw0LjEzLDQuMTMsMCwwLDEtLjY4LTEuNjRDMzcuMjksMjMuMjMsMzcuMzEsMjIuMzQsMzgsMjIuMjNabS0yLjQsNi41N2EuODIuODIsMCwwLDEsMS4xMS0uMTljLjQ1LjIyLjY5LjY3LjUzLDFhLjgyLjgyLDAsMCwxLTEuMTEuMTlDMzUuNywyOS41OCwzNS40NywyOS4xMywzNS42MywyOC44Wm0tMi44LS4zN2MtLjA3LjExLS4yMy4wOS0uNTcuMDZhNC4yNCw0LjI0LDAsMCwwLTIuMTQuMjIsMiwyLDAsMCwxLS40OS4xNC4xNi4xNiwwLDAsMS0uMTEsMCwuMTUuMTUsMCwwLDEtLjA1LS4xMi44MS44MSwwLDAsMSwuMzItLjUxLDIuNDEsMi40MSwwLDAsMSwxLjI3LS41MywxLjk0LDEuOTQsMCwwLDEsMS43NS41N0EuMTkuMTksMCwwLDEsMzIuODMsMjguNDNabS01LjExLTEuMjZjLS4xMiwwLS4xNy0uMDctLjE5LS4xNHMuMjgtLjU2LjYyLS44MWEzLjYsMy42LDAsMCwxLDMuNTEtLjQyQTMsMywwLDAsMSwzMywyNi44N2MuMTIuMi4xNS4zNS4wNy40NHMtLjQ0LDAtLjk1LS4yNGE0LjE4LDQuMTgsMCwwLDAtMi0uNDNBMjEuODUsMjEuODUsMCwwLDAsMjcuNzEsMjcuMTdaIi8+PHBhdGggY2xhc3M9ImNscy0xIiBkPSJNMzUuNSwxMy4yOWMuMSwwLC4xNi0uMTUuMDctLjJhMTEsMTEsMCwwLDAtNC42OS0xLjIzLjA5LjA5LDAsMCwxLS4wNy0uMTQsNC43OCw0Ljc4LDAsMCwxLC44OC0uODkuMDkuMDksMCwwLDAtLjA2LS4xNiwxMi40NiwxMi40NiwwLDAsMC01LjYxLDIsLjA5LjA5LDAsMCwxLS4xMy0uMDksNi4xNiw2LjE2LDAsMCwxLC41OS0xLjQ1LjA4LjA4LDAsMCwwLS4xMS0uMTFBMjIuNzksMjIuNzksMCwwLDAsMjAsMTYuMjRhLjA5LjA5LDAsMCwwLC4xMi4xM0ExOS41MywxOS41MywwLDAsMSwyNywxMy4zMiwxOS4xLDE5LjEsMCwwLDEsMzUuNSwxMy4yOVoiLz48cGF0aCBjbGFzcz0iY2xzLTEiIGQ9Ik0yOC4zNCw2LjQyUzI2LjIzLDQsMjUuNiwzLjhDMjEuNjksMi43NCwxMy4yNCw4LjU3LDcuODQsMTYuMjcsNS42NiwxOS4zOSwyLjUzLDI0LjksNCwyNy43NGExMS40MywxMS40MywwLDAsMCwxLjc5LDEuNzJBNi42NSw2LjY1LDAsMCwxLDEwLDI2Ljc4LDM0LjIxLDM0LjIxLDAsMCwxLDIwLjgsMTEuNjIsNTUuMDksNTUuMDksMCwwLDEsMjguMzQsNi40MloiLz48L2c+PC9nPjwvc3ZnPg=='
);

// Rename the auto-generated first submenu item to "Form Settings".
add_submenu_page(
'mailchimp_sf_options',
esc_html__( 'Form Settings', 'mailchimp' ),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
esc_html__( 'Form Settings', 'mailchimp' ),
esc_html__( 'Mailchimp Form Settings', 'mailchimp' ),

Maybe better to include Mailchimp for page title.

esc_html__( 'Form Settings', 'mailchimp' ),
MCSF_CAP_THRESHOLD,
'mailchimp_sf_options',
array( $this, 'settings_page' )
);
Comment on lines +585 to +592
Copy link

Copilot AI Mar 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add_submenu_page() with the same slug (mailchimp_sf_options) as the top-level menu does not rename the auto-generated first submenu item; it typically results in a duplicate submenu entry pointing to the same page. To actually rename the first submenu item, update the global $submenu['mailchimp_sf_options'][0][0] label after the menu is registered (or remove/replace the auto-generated item via $submenu manipulation).

Suggested change
add_submenu_page(
'mailchimp_sf_options',
esc_html__( 'Form Settings', 'mailchimp' ),
esc_html__( 'Form Settings', 'mailchimp' ),
MCSF_CAP_THRESHOLD,
'mailchimp_sf_options',
array( $this, 'settings_page' )
);
global $submenu;
if ( isset( $submenu['mailchimp_sf_options'][0][0] ) ) {
$submenu['mailchimp_sf_options'][0][0] = esc_html__( 'Form Settings', 'mailchimp' );
}

Copilot uses AI. Check for mistakes.

add_submenu_page(
'admin.php',
esc_html__( 'Create Mailchimp Account', 'mailchimp' ),
Expand Down
Loading
Loading