Skip to content

fix(integrations): skip unconfigured + dedupe health-check alerts#207

Merged
miguelpeixe merged 12 commits into
releasefrom
fix/health-check-alert-flood
Jun 4, 2026
Merged

fix(integrations): skip unconfigured + dedupe health-check alerts#207
miguelpeixe merged 12 commits into
releasefrom
fix/health-check-alert-flood

Conversation

@miguelpeixe

@miguelpeixe miguelpeixe commented Jun 3, 2026

Copy link
Copy Markdown
Member

All Submissions:

Changes proposed in this Pull Request:

Hotfix for the alert flood and ActionScheduler retry flood that started after #4723. Shared root cause: an integration that is enabled-but-unconfigured (e.g. ESP enabled by default but no provider/master list selected) is a setup-incomplete state, not a runtime incident — it should surface in the integrations UI, not in the alerts channel or the AS retry queue.

1. Skip unconfigured integrations across all integration-walking paths.
`Integration::is_set_up()` is now consulted before every cron- or loopback-driven walk, via the new `Integrations::get_active_configured_integrations()` helper:

  • `Integrations::run_health_checks()` — skips the hourly health-check cron.
  • `Contact_Sync::push_to_integrations()` — skips the initial push, preventing the first AS retry row from being scheduled.
  • `Contact_Sync::execute_integration_retry()` — aborts the retry chain when an integration becomes unconfigured between schedule and execute, draining the existing flood without rescheduling.
  • `Contact_Pull::pull_all()` — same skip on the pull side.
  • `Contact_Pull::pull_sync()` — same skip for the per-user synchronous loopback path.
  • `Contact_Pull::handle_ajax_pull()` — defense-in-depth: a direct AJAX call for an unconfigured integration is a silent no-op.
  • `Contact_Pull::execute_integration_retry()` — same retry-chain abort on the pull side.

1a. `ESP::is_set_up()` reads STORED state only.
The implementation now consults two stored options — `newspack_newsletters_service_provider` (provider selected) and the provider's master-list option — instead of calling the live `get_lists()` API. This is required because every gate above uses `is_set_up()`: if it dipped into a live provider call, any transient provider failure (timeout, rate-limit, auth blip) would make every gate skip and silently drop data — exactly the failure mode the AS retry system was built to survive. The setup question "did the admin finish configuring this?" must be answered from local state; "is the provider reachable right now?" is `health_check()`'s job.

2. Dedupe `Alert_Manager::handle_health_check_failed`.
The handler stores a transient keyed on `integration_id + sorted error codes + sorted error messages` with a `DAY_IN_SECONDS` TTL (exposed as `Alert_Manager::HEALTH_CHECK_DEDUP_INTERVAL`). Including the messages in the key (and not only the codes) is intentional: an escalating same-code failure with a worse message (e.g. "list missing" → "auth fully revoked") bypasses the bucket and re-alerts. The trade-off is that messages containing dynamic content (timestamps, IDs) would increase alert volume; current Newspack ESP error messages are static per code so the trade-off lands on the right side. Empty `WP_Error` codes collapse to `[ 'unknown' ]` so a bare `new WP_Error()` shares the bucket with the non-`WP_Error` payload path. The transient is set BEFORE `do_action( 'newspack_alert' )` so a handler that throws (e.g. transient Slack POST failure) cannot leave the key unset and defeat dedup on the next hourly cron.

Together these drop staging-clone and legacy enabled-but-unconfigured noise — both Slack alerts and AS retry rows — to zero, while preserving signal for real, configured-but-broken integrations.

How to test the changes in this Pull Request:

  1. Health check skip — On a site with ESP enabled but no master list configured: run `wp cron event run newspack_integration_health_check`. The `newspack_integration_health_check_failed` action should not fire (verify with `add_action( 'newspack_integration_health_check_failed', fn() => error_log( 'fired' ) )`).
  2. Alert dedup — Force `is_set_up()` to return true (e.g. set a master list ID) and re-run the cron event. The action should fire, but only once per `HEALTH_CHECK_DEDUP_INTERVAL` (24h) per integration + error-code + error-message signature. Delete the transient (`newspack_alert_hc_*` in `wp_options`) and re-run — the alert should fire again.
  3. Escalation re-alert — Force a health-check failure with a given error code/message, let it dedupe, then change the message text for the same code (e.g. `WP_Error( 'connection_failed', 'auth fully revoked' )`). The next dispatch should bypass the bucket and re-alert.
  4. Master-list removal — Configure ESP fully (provider + master list), then clear the master list in the Newsletters settings. `ESP::is_set_up()` should return false on the next check; no new `newspack_contact_sync_retry` rows should appear; no health-check alerts should fire.
  5. Push skip — On a site with ESP enabled but no master list configured, trigger a reader sync (e.g. register a new reader). No `newspack_contact_sync_retry` rows should appear in `wp_actionscheduler_actions` for the ESP integration.
  6. Pull skip — On the same site, trigger `Contact_Cron::maybe_enqueue_contact` (load any page while logged in after the 5-min interval). No `newspack_contact_pull_retry` rows should appear, and no loopback request should be fired for the ESP integration.
  7. Retry drain — With existing pending `newspack_contact_sync_retry` rows from a prior flood, set the integration to `is_set_up()=false` and let the queue execute. Each execution should log "aborting retry chain" and create no new rows; the flood drains naturally as the existing rows complete.
  8. PHPUnit (run from `plugins/newspack-plugin/`):
    • `n test-php --filter 'test_run_health_checks_skips_unconfigured_integrations'`
    • `n test-php --filter 'test_run_health_checks_fires_when_set_up_and_failing'`
    • `n test-php --filter 'test_get_active_configured_integrations_filters_by_is_set_up'`
    • `n test-php --filter 'test_esp_is_set_up_reads_stored_state'`
    • `n test-php --filter 'test_health_check_failed_dedupes_repeated_fires'`
    • `n test-php --filter 'test_health_check_failed_alerts_on_new_error_codes'`
    • `n test-php --filter 'test_health_check_failed_alerts_on_new_error_messages'`
    • `n test-php --filter 'test_health_check_failed_alerts_per_integration'`
    • `n test-php --filter 'test_health_check_failed_sets_dedup_before_dispatch'`
    • `n test-php --filter 'test_execute_integration_retry_aborts_when_not_set_up'`
    • `n test-php --filter 'test_pull_all_skips_unconfigured_integrations'`
    • `n test-php --filter 'test_pull_sync_skips_unconfigured_integrations'`
    • `n test-php --filter 'test_pull_execute_integration_retry_aborts_when_not_set_up'`

The initial-push gate (`Contact_Sync::push_to_integrations`) has no direct unit test — a reflection-based test would also iterate the live ESP whose `push_contact_data` hits `Newspack_Newsletters_Contacts` (not loaded in the unit-test env). The gate is structurally identical to the health-check and pull skips above and is covered by manual test step 5.

Other information:

  • Have you added an explanation of what your changes do and why you'd like us to include them?
  • Have you written new tests for your changes, as applicable?
  • Have you successfully run tests with your changes locally?

This is a hotfix targeted at `release`. Once merged, it should be propagated forward to `alpha` and `main` via the standard branch-promotion flow.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Hotfix to reduce #newspack-errors noise from hourly integration health checks by (1) skipping checks for enabled-but-not-configured integrations and (2) deduplicating repeated health-check failure alerts over a fixed interval.

Changes:

  • Skip Integrations::run_health_checks() for integrations where is_set_up() is false.
  • Add transient-based deduplication in Alert_Manager::handle_health_check_failed() keyed by integration_id + sorted error codes.
  • Add/extend PHPUnit coverage for the skip + dedupe behaviors (including a more configurable Sample_Integration test double).

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
plugins/newspack-plugin/tests/unit-tests/integrations/class-test-integrations.php Adds tests asserting health checks are skipped when is_set_up() is false and still fire when set up + failing.
plugins/newspack-plugin/tests/unit-tests/integrations/class-sample-integration.php Extends the test integration double to simulate setup state and configurable can_sync() error codes.
plugins/newspack-plugin/tests/unit-tests/alert-manager.php Adds tests validating deduplication behavior across repeats, new error signatures, and per-integration isolation.
plugins/newspack-plugin/includes/reader-activation/class-integrations.php Implements the is_set_up() gate in run_health_checks() to avoid treating setup-incomplete integrations as incidents.
plugins/newspack-plugin/includes/class-alert-manager.php Implements deduplication for health-check-failure alerts via a transient key derived from integration + error signature.

Comment thread plugins/newspack-plugin/tests/unit-tests/integrations/class-test-integrations.php Outdated
Comment thread plugins/newspack-plugin/tests/unit-tests/integrations/class-test-integrations.php Outdated
@miguelpeixe miguelpeixe marked this pull request as ready for review June 3, 2026 19:43
@miguelpeixe miguelpeixe requested a review from a team as a code owner June 3, 2026 19:43

@chickenn00dle chickenn00dle left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks for the hotfix @miguelpeixe! I ran this through review and Claude came up with some good points which I've added inline. I should also note that while testing, the ESP integration seems to still think I'm setup even after I removed the master list via settings 😦

I think this might require some more thought. Wdyt about submitting a simpler hotfix to just remove the hook temporarily:

}

foreach ( $integrations as $integration_id => $integration ) {
if ( ! $integration->is_set_up() ) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔴 Silent data loss when the ESP readiness probe transiently fails

is_set_up() for the ESP resolves to Reader_Activation::is_esp_configured()get_enabled_lists()Newspack_Newsletters_Subscription::get_lists(), which always fetches lists live from the ESP (subscription class L165). On a timeout / rate-limit / auth blip it returns a WP_Error, which is_esp_configured() treats as "not an array" and returns false.

So for a fully-configured integration during a momentary provider hiccup, this continue skips the push entirely: push_contact_data is never called, newspack_sync_contact_failed never fires, and no retry is scheduled — the contact update is permanently lost, silently. This inverts the purpose of the retry system, which exists to survive exactly these transient failures.

It also narrows the true|WP_Error contract: push_to_integrations can now return true even though an integration was skipped, so callers like the ras-contact-sync WP-CLI report success for a contact that wasn't pushed.

Suggest gating on a stored readiness signal (provider selected + stored list/master-list config) instead of a live get_lists() call, or failing open when the probe returns WP_Error (treat "unknown" as "don't skip").

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Fixed in dae5bae — root cause was ESP::is_set_up() calling the live get_lists() via Reader_Activation::is_esp_configured(). It now reads stored state only (provider option + master list ID option), so a transient provider failure can't make is_set_up() return false. The push gate (and the rest of the sites that consult is_set_up()) is now safe to skip on. 8b0fc58 also centralizes the skip into Integrations::get_active_configured_integrations() so a 6th walk site can't drift.

return;
}

if ( ! $integration->is_set_up() ) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔴 Aborts an in-flight retry chain on a transient probe failure

Same root cause as the push-path comment above. A retry that was queued because of a real prior failure hits this guard at execution time; if the live is_set_up() ESP call momentarily errors, the chain aborts with no reschedule and no exhaustion record — the queued contact update is dropped. A configured-but-temporarily-unreachable ESP is exactly the case the backoff/retry was built to handle.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Same root cause as the push-path comment. Fixed in dae5baeis_set_up() is now a stored-state check, so this retry guard can't abort a chain because of a transient probe failure.

$errors = [];

foreach ( $active_integrations as $integration ) {
if ( ! $integration->is_set_up() ) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔴 Same transient-failure data loss on the pull side

See the push-path comment in class-contact-sync.php. is_set_up() here also performs a live ESP list fetch, so a transient WP_Error makes it return false and this continue silently drops the pull — incoming fields fail to populate for the user with no retry.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Same root cause. Fixed in dae5bae. The pull gate at this line is also now routed through Integrations::get_active_configured_integrations() (8b0fc58) which uses the stored-state is_set_up().

return;
}

if ( ! $integration->is_set_up() ) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔴 Same retry-chain abort on the pull side

Mirrors the sync retry guard: a transient is_set_up() probe failure permanently aborts the queued pull retry with no reschedule.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Same root cause. Fixed in dae5bae — the stored-state is_set_up() means a transient probe failure can't abort an in-flight pull retry chain.

public static function run_health_checks() {
$active = self::get_active_integrations();
foreach ( $active as $integration ) {
if ( ! $integration->is_set_up() ) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟠 Live ESP I/O on a hot path + a monitoring blind spot + altitude

Three things converge on this is_set_up() skip:

  1. Efficiencyis_set_up() is now a blocking remote ESP call, run on every active integration every hour, immediately before health_check() (which makes more live calls). Adds latency and provider rate-limit pressure to the cron.

  2. Monitoring blind spot — when a previously-working ESP loses its last active list (or the probe itself errors), is_set_up() returns false, so health_check()test_connection() never runs. A genuinely broken connection (revoked key, etc.) is silently reclassified as "setup incomplete" and stops alerting.

  3. Altitude — this is_set_up() skip is now copy-pasted into 5 walk sites (health-check, sync push + retry, pull + retry) with no central "configured integrations" filter, so a 6th walk path added later silently re-introduces the flood. Consider a get_configured_integrations() helper (or get_active_integrations( $configured = true )) plus a shared retry-abort helper for the two identical execute_integration_retry guards.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

All three points addressed:

  1. Efficiencydae5bae: is_set_up() no longer hits the provider. The check now consults two stored options (newspack_newsletters_service_provider + the provider's master-list option).
  2. Monitoring blind spot — also dae5bae: a previously-working ESP that loses its last list (or whose probe errors) keeps is_set_up()=true (master_list_id option still stored). health_check()test_connection() continues to run, and revoked credentials still alert.
  3. Altitude / DRY8b0fc58: added Integrations::get_active_configured_integrations(); the three foreach walks (health check, sync push, pull) route through it now. The two execute_integration_retry guards stayed inline because they differ in logger context — happy to extract a tiny shared helper if you'd prefer.

]
);

set_transient( $dedup_key, time(), self::HEALTH_CHECK_DEDUP_INTERVAL );

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Set the dedup transient before dispatch, not after

If any newspack_alert handler throws on a transient error (e.g. the Slack POST connector), execution never reaches this set_transient, so the next hourly cron re-alerts — dedup is defeated exactly when delivery is flaky. Since the dedup's intent is to cap alert volume rather than guarantee delivery, set the transient before do_action( 'newspack_alert', ... ).

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Fixed in 0654b80set_transient is now called before do_action( 'newspack_alert' ). Added test_health_check_failed_sets_dedup_before_dispatch which registers a throwing listener and asserts the transient is still set after the throw.

$error = $payload['error'] ?? null;
$error = $payload['error'] ?? null;
$integration_id = $payload['integration_id'] ?? 'unknown';
$error_codes = is_wp_error( $error ) ? $error->get_error_codes() : [];

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Dedup keys on error codes only, not messages

An escalating failure that keeps the same code set but carries a worse message (e.g. "list missing" → "auth fully revoked") is suppressed for the full 24h window, so the richer signal never reaches Slack. Worth confirming that's acceptable, or fold a short message hash into the key.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Fixed in 0654b80 — the dedup key now folds WP_Error::get_error_messages() into the md5 alongside the codes. An escalating same-code failure with a worse message now bypasses the bucket and re-alerts. Added test_health_check_failed_alerts_on_new_error_messages. Trade-off noted in the docblock for any future caller passing dynamic content (timestamps/IDs) in the message — for the current Newspack ESP errors, messages are static per code so dedup remains stable.

@github-actions github-actions Bot added [Status] Needs Changes or Feedback Pull request needs changes or feedback and removed [Status] Needs Review labels Jun 3, 2026

@chickenn00dle chickenn00dle left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Approving assuming feedback is addressed!

@github-actions github-actions Bot added [Status] Approved Pull request has been approved and removed [Status] Needs Changes or Feedback Pull request needs changes or feedback labels Jun 3, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated 2 comments.

Comment on lines 160 to 162
public static function pull_all( $user_id ) {
$active_integrations = Integrations::get_active_integrations();
$active_integrations = Integrations::get_active_configured_integrations();
$errors = [];

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Good catch — Fixed in a8cea54. Contact_Pull::pull_sync() now defaults to Integrations::get_active_configured_integrations(), and handle_ajax_pull() has a defense-in-depth check that silently succeeds for an unconfigured integration (so a direct AJAX call can't bypass the gate). Added test_pull_sync_skips_unconfigured_integrations which registers a configured and an unconfigured mock and asserts only the configured one receives a loopback. The other remaining get_active_integrations() callers (register_group_labels, register_my_account_endpoints, promoted-fields, Sync::has_one_syncable_integration) are intentionally kept — they're registration/UI/has-any checks, not integration-walking I/O, so the configured filter doesn't apply.

Comment on lines +463 to +480
* Deduplicates by integration + error-code + error-message signature
* for HEALTH_CHECK_DEDUP_INTERVAL so an hourly cron does not repeat
* the same Slack alert all day. A new error code OR a changed message
* on the same integration (e.g. "list missing" escalating to "auth
* fully revoked") falls outside the key and alerts immediately.
*
* @param array $payload Health check failure data.
*/
public static function handle_health_check_failed( $payload ) {
$error = $payload['error'] ?? null;
$error = $payload['error'] ?? null;
$integration_id = $payload['integration_id'] ?? 'unknown';
$error_codes = is_wp_error( $error ) ? $error->get_error_codes() : [];
if ( empty( $error_codes ) ) {
$error_codes = [ 'unknown' ];
}
$error_messages = is_wp_error( $error ) ? $error->get_error_messages() : [];

$dedup_key = self::get_health_check_dedup_key( $integration_id, $error_codes, $error_messages );

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Right — PR description updated. The 'Changes proposed' section now states the dedup key is integration_id + sorted error codes + sorted error messages and explicitly calls out the trade-off (escalating same-code failures re-alert; dynamic content in messages would inflate alert volume — current Newspack ESP messages are static per code so it lands on the right side). The change came out of @chickenn00dle's feedback on the prior codes-only signature; test_health_check_failed_alerts_on_new_error_messages pins the new behavior.

@miguelpeixe miguelpeixe merged commit 63eebb9 into release Jun 4, 2026
8 checks passed
@github-actions

github-actions Bot commented Jun 4, 2026

Copy link
Copy Markdown

Hey @miguelpeixe, good job getting this PR merged! 🎉

Now, the needs-changelog label has been added to it.

Please check if this PR needs to be included in the "Upcoming Changes" and "Release Notes" doc. If it doesn't, simply remove the label.

If it does, please add an entry to our shared document, with screenshots and testing instructions if applicable, then remove the label.

Thank you! ❤️

matticbot pushed a commit that referenced this pull request Jun 4, 2026
## newspack [6.42.4](https://github.com/Automattic/newspack-workspace/compare/newspack@6.42.3...newspack@6.42.4) (2026-06-04)

### Bug Fixes

* **integrations:** skip unconfigured + dedupe health-check alerts ([#207](#207)) ([63eebb9](63eebb9))
matticbot pushed a commit that referenced this pull request Jun 5, 2026
## [4.26.5-alpha.1](https://github.com/Automattic/newspack-workspace/compare/@automattic/newspack-blocks@4.26.4...@automattic/newspack-blocks@4.26.5-alpha.1) (2026-06-05)

### Bug Fixes

* add contrasting colour to the my account mobile menu button ([#164](#164)) ([c06219c](c06219c))
* add contrasting colour to the my account mobile menu button ([#164](#164)) ([94b765c](94b765c))
* **audience:** decode HTML entities in campaign prompt titles ([#4711](https://github.com/Automattic/newspack-workspace/issues/4711)) ([f1d189b](f1d189b))
* **blocks:** restore allow-duplicate toggle for static blocks ([#180](#180)) ([8aaa75e](8aaa75e))
* **ci:** restore workspace:* deps in post-release branch maintenance ([#139](#139)) ([821630b](821630b))
* correct submit button text on change-payment-method page ([#4654](https://github.com/Automattic/newspack-workspace/issues/4654)) ([7aba1ff](7aba1ff))
* **editor:** keep legacy CSS vars in sync with newsletters-prefixed ones ([#2140](https://github.com/Automattic/newspack-workspace/issues/2140)) ([4f3c33a](4f3c33a))
* **group-subscription:** update params; avoid secondary My Account redirect ([#151](#151)) ([c5f6249](c5f6249))
* **integrations:** skip unconfigured + dedupe health-check alerts ([#207](#207)) ([63eebb9](63eebb9))
* **jetpack:** disable Newsletter (subscriptions) module ([#208](#208)) ([7d56e9d](7d56e9d))
* **n:** correct worktree-to-env routing ([#152](#152)) ([f8bf0c2](f8bf0c2))
* **newsletters:** clear false "unsaved changes" prompt after save ([#190](#190)) ([265f0dc](265f0dc))
* **newspack-blocks:** update swiper to patched release ([a33812a](a33812a))
* **newspack-network:** patch critical basic-ftp alert ([a2c8802](a2c8802))
* **newspack-theme:** apply ad background color to Broadstreet ads ([#167](#167)) ([fbf469f](fbf469f))
* **popups:** portal overlays to wp_footer to escape stacking contexts ([797c42c](797c42c))
* **posts-inserter:** show placeholder when block has zero posts ([#166](#166)) ([c269ff2](c269ff2))
* prevent content-gate editor.scss styles from getting chunked into the common.css file ([#4716](https://github.com/Automattic/newspack-workspace/issues/4716)) ([f6e5a56](f6e5a56))
* quote additional site names and derivatives ([#66](#66)) ([9a377db](9a377db))
* **reader-activation:** clear localStorage namespace on logout ([#145](#145)) ([c201ad5](c201ad5))
* **reader-activation:** exclude peeking newsletter from a11y tree ([#4744](https://github.com/Automattic/newspack-workspace/issues/4744)) ([b726bbf](b726bbf))
* render synced patterns inside Group blocks in newsletters ([#2069](https://github.com/Automattic/newspack-workspace/issues/2069)) ([b09da75](b09da75))
* **theme:** square icon-only buttons via theme.json variations ([#452](https://github.com/Automattic/newspack-workspace/issues/452)) ([fb1493d](fb1493d))
* update paragraph markup to fix failing tests ([2fbadaa](2fbadaa))

### Features

* **block-theme:** add search overlay block ([#4729](https://github.com/Automattic/newspack-workspace/issues/4729)) ([0ebac0d](0ebac0d))
* **integrations:** add inactive plugin state ([#4721](https://github.com/Automattic/newspack-workspace/issues/4721)) ([d67ffe0](d67ffe0))
* **integrations:** add oauth and hidden field types ([#4639](https://github.com/Automattic/newspack-workspace/issues/4639)) ([8bd0e7c](8bd0e7c))
* **integrations:** allow filtering integration settings list ([#224](#224)) ([af0a884](af0a884))
* **n:** auto-discover repos/{plugins,themes} checkouts, no registration ([#178](#178)) ([961fe1c](961fe1c))
* **n:** mount standalone plugins from repos/ for local development ([#177](#177)) ([dafcf70](dafcf70))
* **reader-auth:** unify auth + post-reg verification flows ([#135](#135)) ([f67bb65](f67bb65)), closes [#signin_modal](https://github.com/Automattic/newspack-workspace/issues/signin_modal) [#register_modal](https://github.com/Automattic/newspack-workspace/issues/register_modal)
* **wc-subscriptions:** recover switch proration when no amount paid ([#4745](https://github.com/Automattic/newspack-workspace/issues/4745)) ([f9db7a7](f9db7a7))
matticbot pushed a commit that referenced this pull request Jun 5, 2026
# [3.34.0-alpha.1](https://github.com/Automattic/newspack-workspace/compare/newspack-newsletters@3.33.6...newspack-newsletters@3.34.0-alpha.1) (2026-06-05)

### Bug Fixes

* add contrasting colour to the my account mobile menu button ([#164](#164)) ([c06219c](c06219c))
* **audience:** decode HTML entities in campaign prompt titles ([#4711](https://github.com/Automattic/newspack-workspace/issues/4711)) ([f1d189b](f1d189b))
* **blocks:** restore allow-duplicate toggle for static blocks ([#180](#180)) ([8aaa75e](8aaa75e))
* **ci:** restore workspace:* deps in post-release branch maintenance ([#139](#139)) ([821630b](821630b))
* correct submit button text on change-payment-method page ([#4654](https://github.com/Automattic/newspack-workspace/issues/4654)) ([7aba1ff](7aba1ff))
* **editor:** keep legacy CSS vars in sync with newsletters-prefixed ones ([#2140](https://github.com/Automattic/newspack-workspace/issues/2140)) ([4f3c33a](4f3c33a))
* **integrations:** skip unconfigured + dedupe health-check alerts ([#207](#207)) ([63eebb9](63eebb9))
* **jetpack:** disable Newsletter (subscriptions) module ([#208](#208)) ([7d56e9d](7d56e9d))
* **n:** correct worktree-to-env routing ([#152](#152)) ([f8bf0c2](f8bf0c2))
* **newsletters:** clear false "unsaved changes" prompt after save ([#190](#190)) ([265f0dc](265f0dc))
* **newspack-blocks:** update swiper to patched release ([a33812a](a33812a))
* **newspack-network:** patch critical basic-ftp alert ([a2c8802](a2c8802))
* prevent content-gate editor.scss styles from getting chunked into the common.css file ([#4716](https://github.com/Automattic/newspack-workspace/issues/4716)) ([f6e5a56](f6e5a56))
* quote additional site names and derivatives ([#66](#66)) ([9a377db](9a377db))
* **reader-activation:** clear localStorage namespace on logout ([#145](#145)) ([c201ad5](c201ad5))
* **reader-activation:** exclude peeking newsletter from a11y tree ([#4744](https://github.com/Automattic/newspack-workspace/issues/4744)) ([b726bbf](b726bbf))
* render synced patterns inside Group blocks in newsletters ([#2069](https://github.com/Automattic/newspack-workspace/issues/2069)) ([b09da75](b09da75))
* **theme:** square icon-only buttons via theme.json variations ([#452](https://github.com/Automattic/newspack-workspace/issues/452)) ([fb1493d](fb1493d))
* update paragraph markup to fix failing tests ([2fbadaa](2fbadaa))

### Features

* **block-theme:** add search overlay block ([#4729](https://github.com/Automattic/newspack-workspace/issues/4729)) ([0ebac0d](0ebac0d))
* **integrations:** add inactive plugin state ([#4721](https://github.com/Automattic/newspack-workspace/issues/4721)) ([d67ffe0](d67ffe0))
* **integrations:** add oauth and hidden field types ([#4639](https://github.com/Automattic/newspack-workspace/issues/4639)) ([8bd0e7c](8bd0e7c))
* **integrations:** allow filtering integration settings list ([#224](#224)) ([af0a884](af0a884))
* **n:** auto-discover repos/{plugins,themes} checkouts, no registration ([#178](#178)) ([961fe1c](961fe1c))
* **n:** mount standalone plugins from repos/ for local development ([#177](#177)) ([dafcf70](dafcf70))
* **reader-auth:** unify auth + post-reg verification flows ([#135](#135)) ([f67bb65](f67bb65)), closes [#signin_modal](https://github.com/Automattic/newspack-workspace/issues/signin_modal) [#register_modal](https://github.com/Automattic/newspack-workspace/issues/register_modal)
* **wc-subscriptions:** recover switch proration when no amount paid ([#4745](https://github.com/Automattic/newspack-workspace/issues/4745)) ([f9db7a7](f9db7a7))
matticbot pushed a commit that referenced this pull request Jun 5, 2026
## [1.28.4-alpha.1](https://github.com/Automattic/newspack-workspace/compare/newspack-block-theme@1.28.3...newspack-block-theme@1.28.4-alpha.1) (2026-06-05)

### Bug Fixes

* add contrasting colour to the my account mobile menu button ([#164](#164)) ([c06219c](c06219c))
* add contrasting colour to the my account mobile menu button ([#164](#164)) ([94b765c](94b765c))
* **audience:** decode HTML entities in campaign prompt titles ([#4711](https://github.com/Automattic/newspack-workspace/issues/4711)) ([f1d189b](f1d189b))
* **blocks:** restore allow-duplicate toggle for static blocks ([#180](#180)) ([8aaa75e](8aaa75e))
* **ci:** restore workspace:* deps in post-release branch maintenance ([#139](#139)) ([821630b](821630b))
* correct submit button text on change-payment-method page ([#4654](https://github.com/Automattic/newspack-workspace/issues/4654)) ([7aba1ff](7aba1ff))
* **editor:** keep legacy CSS vars in sync with newsletters-prefixed ones ([#2140](https://github.com/Automattic/newspack-workspace/issues/2140)) ([4f3c33a](4f3c33a))
* **group-subscription:** update params; avoid secondary My Account redirect ([#151](#151)) ([c5f6249](c5f6249))
* **integrations:** skip unconfigured + dedupe health-check alerts ([#207](#207)) ([63eebb9](63eebb9))
* **jetpack:** disable Newsletter (subscriptions) module ([#208](#208)) ([7d56e9d](7d56e9d))
* **n:** correct worktree-to-env routing ([#152](#152)) ([f8bf0c2](f8bf0c2))
* **newsletters:** clear false "unsaved changes" prompt after save ([#190](#190)) ([265f0dc](265f0dc))
* **newspack-blocks:** update swiper to patched release ([a33812a](a33812a))
* **newspack-network:** patch critical basic-ftp alert ([a2c8802](a2c8802))
* **newspack-theme:** apply ad background color to Broadstreet ads ([#167](#167)) ([fbf469f](fbf469f))
* **popups:** portal overlays to wp_footer to escape stacking contexts ([797c42c](797c42c))
* **posts-inserter:** show placeholder when block has zero posts ([#166](#166)) ([c269ff2](c269ff2))
* prevent content-gate editor.scss styles from getting chunked into the common.css file ([#4716](https://github.com/Automattic/newspack-workspace/issues/4716)) ([f6e5a56](f6e5a56))
* quote additional site names and derivatives ([#66](#66)) ([9a377db](9a377db))
* **reader-activation:** clear localStorage namespace on logout ([#145](#145)) ([c201ad5](c201ad5))
* **reader-activation:** exclude peeking newsletter from a11y tree ([#4744](https://github.com/Automattic/newspack-workspace/issues/4744)) ([b726bbf](b726bbf))
* render synced patterns inside Group blocks in newsletters ([#2069](https://github.com/Automattic/newspack-workspace/issues/2069)) ([b09da75](b09da75))
* **theme:** square icon-only buttons via theme.json variations ([#452](https://github.com/Automattic/newspack-workspace/issues/452)) ([fb1493d](fb1493d))
* update paragraph markup to fix failing tests ([2fbadaa](2fbadaa))

### Features

* **block-theme:** add search overlay block ([#4729](https://github.com/Automattic/newspack-workspace/issues/4729)) ([0ebac0d](0ebac0d))
* **integrations:** add inactive plugin state ([#4721](https://github.com/Automattic/newspack-workspace/issues/4721)) ([d67ffe0](d67ffe0))
* **integrations:** add oauth and hidden field types ([#4639](https://github.com/Automattic/newspack-workspace/issues/4639)) ([8bd0e7c](8bd0e7c))
* **integrations:** allow filtering integration settings list ([#224](#224)) ([af0a884](af0a884))
* **n:** auto-discover repos/{plugins,themes} checkouts, no registration ([#178](#178)) ([961fe1c](961fe1c))
* **n:** mount standalone plugins from repos/ for local development ([#177](#177)) ([dafcf70](dafcf70))
* **reader-auth:** unify auth + post-reg verification flows ([#135](#135)) ([f67bb65](f67bb65)), closes [#signin_modal](https://github.com/Automattic/newspack-workspace/issues/signin_modal) [#register_modal](https://github.com/Automattic/newspack-workspace/issues/register_modal)
* **wc-subscriptions:** recover switch proration when no amount paid ([#4745](https://github.com/Automattic/newspack-workspace/issues/4745)) ([f9db7a7](f9db7a7))
@miguelpeixe miguelpeixe deleted the fix/health-check-alert-flood branch June 10, 2026 14:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

[Status] Approved Pull request has been approved

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants