Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support send lists in ESP classes #1631

Merged
merged 9 commits into from
Sep 9, 2024

Conversation

dkoo
Copy link
Contributor

@dkoo dkoo commented Aug 29, 2024

All Submissions:

Changes proposed in this Pull Request:

To be reviewed after #1629 (the base for this PR).

  • Adds get_send_lists() methods to all ESP classes and to the Newspack_Newsletters_ESP_API_Interface schema
  • Refactors get_lists() and get_segments() methods for some ESPs to allow for query args (so we only fetch those we need to, where the ESP's API supports filtering by name or IDs)
  • Standardizes senderEmail, senderName, send_list_id and send_sublist_id meta fields to store that info in a standard format across all ESPs
  • Deprecates and migrates provider-specific meta fields that are no longer needed due to the standardized fields
  • Refactors retrieve and sync methods for all ESPs for greater consistency in the newsletterData output (all ESPs will now include lists and sublists keys to store send lists fetched from the ESP)
  • Adds caching of Mailchimp audiences in addition to groups/tags/segments

How to test the changes in this Pull Request:

  1. In wp shell, try out the new get_send_lists() methods. e.g. for MC:
> $esp = Newspack_Newsletters::get_service_provider_instance( 'mailchimp' )
= Newspack_Newsletters_Mailchimp {#2377
    +service: "mailchimp",
    +name: "Mailchimp",
    +controller: Newspack_Newsletters_Mailchimp_Controller {#2378},
  }

> $esp->get_send_lists()

> $esp->get_send_lists( [ 'type' => 'sublist' ] )

> $esp->get_send_lists( [ 'ids' => [ '123, '456' ] ] ) // where the IDs are actual list or sublist IDs from your connected ESP account
  1. For MC, trigger the cache refresh and ensure that audience data is cached:
> wp cron event run newspack_nl_mailchimp_refresh_cache
Executed the cron event 'newspack_nl_mailchimp_refresh_cache' in 1.023s.

> wp option get newspack_nl_mailchimp_cache_lists
array (
  0 =>
  array (
    'id' => '123',
    'web_id' => 456
    'name' => 'My Audience',
    'stats' =>
    array (
      'member_count' => 47,
    ),
  ),
)
  1. Check out the new retrieve output:
> $esp = Newspack_Newsletters::get_service_provider_instance( 'mailchimp' )
= Newspack_Newsletters_Mailchimp {#2377
    +service: "mailchimp",
    +name: "Mailchimp",
    +controller: Newspack_Newsletters_Mailchimp_Controller {#2378},
  }

> $data = $esp->retrieve( $post_id ) // where $post_id is a newsletter post
  1. Ensure that the retrieve output includes list and sublist params:
> $data['lists']
= [
    Newspack\Newsletters\Send_List {#14951
      +"provider": "mailchimp",
      +"type": "list",
      +"entity_type": "audience",
      +"id": "123",
      +"name": "My Audience",
      +"count": 47,
      +"edit_link": "https://us10.admin.mailchimp.com/audience/contacts/?id=456",
      +"value": "123",
      +"label": "[AUDIENCE] My Audience (47 contacts)",
    },
  ]

> $data['sublists']
= [
    Newspack\Newsletters\Send_List {#14911
      +"provider": "mailchimp",
      +"type": "sublist",
      +"entity_type": "group",
      +"id": "789",
      +"name": "My Group",
      +"count": 15,
      +"edit_link": "https://us10.admin.mailchimp.com/audience/groups/?id=654",
      +"value": "789",
      +"label": "[GROUP] My Group (15 contacts)",
    },
  ]

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 ran tests with your changes locally?

@dkoo dkoo requested a review from a team as a code owner August 29, 2024 17:25
@dkoo dkoo self-assigned this Aug 29, 2024
@dkoo dkoo changed the base branch from epic/update-editor-uis to feat/send-lists September 3, 2024 15:08
Base automatically changed from feat/send-lists to epic/update-editor-uis September 3, 2024 15:32
Copy link

codecov bot commented Sep 3, 2024

Codecov Report

Attention: Patch coverage is 3.31263% with 934 lines in your changes missing coverage. Please review.

Project coverage is 21.36%. Comparing base (5a44389) to head (896c900).
Report is 1 commits behind head on epic/update-editor-uis.

Files with missing lines Patch % Lines
...mailchimp/class-newspack-newsletters-mailchimp.php 0.76% 261 Missing ⚠️
...ct/class-newspack-newsletters-constant-contact.php 6.73% 194 Missing ⚠️
...ign/class-newspack-newsletters-active-campaign.php 3.29% 176 Missing ⚠️
...or/class-newspack-newsletters-campaign-monitor.php 3.47% 139 Missing ⚠️
includes/class-newspack-newsletters.php 0.00% 58 Missing ⚠️
...ass-newspack-newsletters-mailchimp-cached-data.php 5.55% 51 Missing ⚠️
...lass-newspack-newsletters-constant-contact-sdk.php 0.00% 26 Missing ⚠️
includes/class-send-lists.php 0.00% 11 Missing ⚠️
...lass-newspack-newsletters-mailchimp-controller.php 0.00% 5 Missing ⚠️
...wspack-newsletters-constant-contact-controller.php 0.00% 3 Missing ⚠️
... and 6 more
Additional details and impacted files
@@                     Coverage Diff                      @@
##             epic/update-editor-uis    #1631      +/-   ##
============================================================
- Coverage                     21.91%   21.36%   -0.55%     
- Complexity                     2443     2594     +151     
============================================================
  Files                            48       48              
  Lines                          9185     9510     +325     
============================================================
+ Hits                           2013     2032      +19     
- Misses                         7172     7478     +306     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

Copy link
Contributor

@leogermani leogermani left a comment

Choose a reason for hiding this comment

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

This is monumental!

I think this is the most important and impactful refactor we (you) are doing as part of the current efforts to improve the plugin stability. When we first starting discussion how we should improve the abstraction we were talking precisly about this. We knew it was a lot of work, and you nailed it!

I left one comment regarding the change on how the mailchimp cache is refreshed.

I'm seeing this warning, not 100% sure it is related to this PR:

 PHP Notice:  Function register_rest_route was called <strong>incorrectly</strong>. Namespace must not start or end with a slash.

btw, I see you are removing register_rest_route from the ESP classes, but I missed where they are going. I though I would see them in the parent class but I didn't. We don't need them anymore? Are they being added in a next PR?

Also this:

Cron reschedule event error for hook: newspack_nl_mailchimp_refresh_cache, Error code: invalid_schedule, Error message: Event schedule does not exist., Data: {"schedule":"every_10_minutes","args":[],"interval":600}

At one point, I also saw this error:

PHP Fatal error:  Uncaught TypeError: array_map(): Argument #2 ($array) must be of type array, WP_Error given in /newspack-repos/newspack-newsletters/includes/service-providers/constant_contact/class-newspack-newsletters-constant-contact.php:989

After switching back and forth between providers, it worked (my connection was authorized).

I think what happens is that the CC API is very flaky, so we need to be extra careful there. But maybe some similar error handling in other places where we just throw result of a method into an array_* function is desired.


I've read through the changes and ran the tests you suggested, in all ESPs. Changes look good! Maybe a few things passed but I'm assuming we can catch them in a more complete tests when we test the full integration with the front-end.

@@ -461,35 +502,83 @@ private static function refresh_cached_data( $list_id ) {
*/
public static function handle_cron() {
Newspack_Newsletters_Logger::log( 'Mailchimp cache: Handling cron request to refresh cache' );
$lists = self::get_lists();
Copy link
Contributor

@leogermani leogermani Sep 3, 2024

Choose a reason for hiding this comment

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

Is this really needed?

It was intentional that each list cache should be refreshed in its own request. Even though we run them async, these requests can still timeout. And I know for a fact that in some sites with many Audiences, tags, groups, etc, trying to fetch everything from all lists at once will timeout.

Breaking it in chunks of lists, and refreshing them separate, was to avoid that. This would be a very hard thing to catch if it started failing.

If there isn't any strong reasons why we need this, I think we should leave it as it is - and maybe add a comment with the reasoning so we don't fall in the same trap again in the future.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hmm, in trunk it looks like we're fetching all lists and refreshing the cache for all here too.

The only difference in this PR is that we use the cached lists if they haven't expired (get_lists() will fetch if the cache is older than 10 minutes).

Copy link
Contributor

Choose a reason for hiding this comment

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

Let me look at the diff with fresh eyes again on Monday. I thought there was a change in behavior that would refresh the cache for all lists in the same request. It it's not that it's fine

Copy link
Contributor Author

@dkoo dkoo Sep 6, 2024

Choose a reason for hiding this comment

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

Ah, I see what you mean. In this diff we're introducing caching of list data. But that doesn't mean we fetch and cache all of the list's sublists at the same time. It just means we're caching the lists array from the MC API /lists response. We still iterate through each list object and dispatch a separate refresh request for each list—this is unchanged from trunk.

		foreach ( $lists as $list ) {
			Newspack_Newsletters_Logger::log( 'Mailchimp cache: Dispatching request to refresh cache for list ' . $list['id'] );
			self::dispatch_refresh( $list['id'] );
		}

@dkoo
Copy link
Contributor Author

dkoo commented Sep 6, 2024

I'm seeing this warning, not 100% sure it is related to this PR:

Yep, this should be fixed in b28ca0c.

btw, I see you are removing register_rest_route from the ESP classes, but I missed where they are going. I though I would see them in the parent class but I didn't. We don't need them anymore? Are they being added in a next PR?

These will no longer be needed after the changes in the next PR, because the ESP-specific REST routes to get lists/segments/etc. have been replaced by the Send Lists API, and the ESP-specific routes to set lists/segments/etc. on a campaign will happen as part of the sync request that's dispatched after we update the email HTML upon save—so there won't need to be any separate REST requests to get or set those things.

At one point, I also saw this error:

Yes, good call. e300157 adds error handling for the get_send_lists() methods.

@dkoo dkoo requested a review from leogermani September 6, 2024 19:07
@github-actions github-actions bot added [Status] Approved Ready to merge and removed [Status] Needs Review labels Sep 9, 2024
@dkoo dkoo merged commit 1ed1e50 into epic/update-editor-uis Sep 9, 2024
11 checks passed
@dkoo dkoo deleted the feat/send-lists-esp-includes branch September 9, 2024 16:05
'type' => 'sublist',
]
);
if ( ! empty( $sublist[0]->get_entity_type() ) ) {
Copy link
Member

Choose a reason for hiding this comment

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

While testing #1632 I found that this is throwing a fatal error when attempting to send a test email:

[11-Sep-2024 16:20:02 UTC] PHP Fatal error:  Uncaught Error: Call to a member function get_entity_type() on array in newspack-newsletters/includes/service-providers/mailchimp/class-newspack-newsletters-mailchimp.php:972

Copy link
Member

Choose a reason for hiding this comment

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

The same error occurred while trying to send the email

Copy link
Member

Choose a reason for hiding this comment

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

dkoo added a commit that referenced this pull request Oct 14, 2024
* feat: make "Send To" UI autocomplete instead of dropdowns (#1577)

* feat: autocomplete "Send To" UI for CC + AC

* fix: sent post statuses for AC

* feat: autocomplete send-to UI for Mailchimp

* fix: support _n() contacts in AC + CC

* refactor: standardize "sent" status checks for all ESPs

* fix: function name for CC

* fix: set list_type for audiences

* fix: extra parentheses for AC

* feat: show suggestions on focus

* style: move external "Manage" links to button

* feat: design updates for autocomplete UI

* fix: send to summary

* fix: contact counts in send to summary

* fix: mailchimp and selected list styles

* fix: remove ID from AC segments

* fix: logic for contact count in send to summary

* fix: parse contact counts as int to avoid "1 contacts" output

* fix: translation strings for contact counts in summaries

* refactor: standardize use of renderSelectedSummary functions

* fix: translatable send-to summaries

* fix: allow 0 to be shown

* fix: grammar

* Update src/service-providers/active_campaign/ProviderSidebar.js

Co-authored-by: leogermani <leogermani@automattic.com>

* Update src/service-providers/active_campaign/ProviderSidebar.js

Co-authored-by: leogermani <leogermani@automattic.com>

* Update src/service-providers/constant_contact/ProviderSidebar.js

Co-authored-by: leogermani <leogermani@automattic.com>

* Update src/service-providers/constant_contact/ProviderSidebar.js

Co-authored-by: leogermani <leogermani@automattic.com>

* Update src/service-providers/mailchimp/ProviderSidebar.js

Co-authored-by: leogermani <leogermani@automattic.com>

* Update src/service-providers/mailchimp/ProviderSidebar.js

Co-authored-by: leogermani <leogermani@automattic.com>

* fix: translatable strings in SendTo component’s selected item label

---------

Co-authored-by: leogermani <leogermani@automattic.com>

* fix(editor): render notice on sync error (#1606)

* fix(mailchimp): improve sync error messages (#1619)

* fix(activecampaign): default message on request error (#1618)

* feat: cross-ESP send-lists

* refactor: move API namespace and permission callback to main class

* feat: support send lists in provider classes

* feat: refactor editor JS to use new standardized data

* fix: ensure Newsletters plugin blocks are grouped under Newspack category (#1630)

* feat: send list classes (#1629)

* feat: cross-ESP send-lists

* refactor: move API namespace and permission callback to main class

* refactor: feedback from code review

* fix: add missing get/set methods for count and parent_id

* refactor: more consistent naming for set_count method

* refactor: maintain exception but with WP_Error handling

* docs: add more explanation about Send_Lists

Co-authored-by: leogermani <leogermani@automattic.com>

* test: improve tests for matching methods

* refactor: set values on protected $config var

* docs: tweak wording of explanation

---------

Co-authored-by: leogermani <leogermani@automattic.com>

* feat: support send lists in ESP classes (#1631)

* feat: cross-ESP send-lists

* refactor: move API namespace and permission callback to main class

* feat: support send lists in provider classes

* fix: use getter methods for Send_List classes

* chore: clean up register_rest_route configs and permission callbacks

* fix: improve error handling for get_send_list methods

* fix: add error handling to send-lists API handler

* fix: return Send_List objects as arrays from provider methods

* fix: avoid unnecessary send-list API requests

* chore: remove unneeded methods

* fix: fatal error due to get_send_lists returning Send_List arrays instead of objects

* Revert "fix: fatal error due to get_send_lists returning Send_List arrays instead of objects"

This reverts commit 3ff1e65.

* fix: allow get_send_list methods to return either Send_List[] or arrays

* fix: correct type for supportedESPs fallback value

* fix(mc): subscriber send count in pre-send modal summary

* fix: formatting error

* fix: ensure supported_esps is an array, not an object

* fix: missed callable

* fix: cc error handling

* fix: better error handling for retrieve/sync request errors

* refactor: unify retrieve error handling across all ESPs

* refactor: throw error for missing MC creds, too

* test: update expected exception message

* refactor: consolidate ESP data getters into Redux store

* docs: update inline docs for Redux store

* fix: move SendTo to Sidebar component; avoid parallel retrieve requests

* refactor: always prefetch sublists on list select

* fix: account for missing selected list or sublist info

* fix: default sender/send-to for saved layouts

* fix: campaign_defaults meta field name

* fix: don't overwrite fetched lists/sublists info on retrieve

* fix: force release

* feat: add link to campaign in provider (#1661)

* fix: parse legacy layout defaults (#1663)

* fix: handle legacy layout defaults for MC

* fix: legacy layout defaults for AC + CC

* fix: senderName + senderEmail for AC

---------

Co-authored-by: leogermani <leogermani@automattic.com>
Co-authored-by: Miguel Peixe <miguel.peixe@a8c.com>
Co-authored-by: Miguel Peixe <miguel.peixe@automattic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Status] Approved Ready to merge
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants