feat(access-control): filter available lists by content restrictions#4589
feat(access-control): filter available lists by content restrictions#4589
Conversation
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
| $email = $request['email_address']; | ||
|
|
||
| // If the email address is associated with a different user, use that user's ID for evaluating content restrictions for the signup form. | ||
| // TODO: Maybe check this against the result of self::set_current_reader()? | ||
| $user = get_user_by( 'email', $email ); | ||
| if ( $user && $user->ID !== get_current_user_id() ) { | ||
| self::$current_reader_user_id = $user->ID; | ||
| add_filter( 'newspack_content_restriction_control_user_id', [ self::class, 'get_user_id_for_content_restriction' ] ); | ||
| } | ||
| ob_start(); | ||
| self::render_newsletters_signup_modal( $request['email_address'] ); | ||
| self::render_newsletters_signup_modal( $email ); | ||
| $html = trim( ob_get_clean() ); | ||
|
|
||
| // Reset the current reader user ID so it doesn't affect other operations in this session. | ||
| if ( $user && $user->ID !== get_current_user_id() ) { | ||
| self::$current_reader_user_id = 0; | ||
| remove_filter( 'newspack_content_restriction_control_user_id', [ self::class, 'get_user_id_for_content_restriction' ] ); | ||
| } |
There was a problem hiding this comment.
This looks a bit convoluted... Is it not possible to set an X-WP-Nonce header when fetching this data from refreshNewslettersSignupModal() and rely on the current user?
There was a problem hiding this comment.
The challenge is that when this REST API request is fired, it happens right before the reader account is registered and authenticated, so the current user isn't available yet in this execution.
There was a problem hiding this comment.
I'm confused... How does it set $current_reader_user_id then?
There was a problem hiding this comment.
I think we can continue discussing a solution for this, but it's best tackled in a separate PR since it might touch other flows outside of premium newsletters.
There was a problem hiding this comment.
Forgot to respond to this, sorry!
I'm confused... How does it set
$current_reader_user_idthen?
The api_render_newsletters_signup_form callback can run in an unauthenticated OR an authenticated session:
- If an anonymous reader registers for a new account or completes a Woo purchase, it will fire in an unauthenticated session as the reader account is created on the server
- If the reader is already logged in and completes a Woo purchase, it will fire in the authenticated session
In the first scenario, get_current_user_id() will return 0, so we can compare that to the $user we fetch via the passed email address. In this case, we assume that the passed email address is the brand-new user account that was just created and cache that user ID for the sole purpose of rendering the newsletter signup modal.
In the second scenario, get_current_user_id() will return the correct user ID, so no further action is needed.
miguelpeixe
left a comment
There was a problem hiding this comment.
Tests well! Thank you for the revisions.
I'm working on improving the session hydration handling for the post-checkout premium newsletter offering in #4618.
I'm still able to see restricted newsletters in the My Account -> Newsletters page, but let's tackle it in a separate PR.
|
Hmm... I can actually see restricted newsletters in the newsletter sign-up modal and on the My Account page, regardless of my access. I had them unchecked in the "Present newsletter signup after checkout and registration" while first testing, and toggled them on after purchasing the subscription. That's why I missed it. |
|
@miguelpeixe is your Newsletters plugin running the required branch? |
|
Not this time around 🤦 |
|
Hey @dkoo, good job getting this PR merged! 🎉 Now, the 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! ❤️ |
# [6.37.0-alpha.1](v6.36.1...v6.37.0-alpha.1) (2026-04-02) ### Bug Fixes * **card-settings-group:** change default actionType from chevron to none ([#4610](#4610)) ([00505ed](00505ed)) * **post-date:** preserve classic theme markup and fix archive titles ([#4602](#4602)) ([c5fb825](c5fb825)) * remove removal of block visibility ([#4595](#4595)) ([9396379](9396379)) ### Features * **access-control:** filter available lists by content restrictions ([#4589](#4589)) ([959127f](959127f)), closes [#4581](#4581) [#4583](#4583) [#4590](#4590) * **access-control:** premium newsletters UI ([#4577](#4577)) ([6f8c891](6f8c891)), closes [#4581](#4581) [#4583](#4583) [#4590](#4590) * **author-profile-social:** add support for colors, block spacing, brand style ([#4509](#4509)) ([21cf4c9](21cf4c9)) * campaigns wizard light UI refresh ([#4588](#4588)) ([6078c4b](6078c4b)) * **color-picker:** simplify component to use basecontrol ([#4581](#4581)) ([ff677ea](ff677ea)) * **components:** add CardFeature component ([#4583](#4583)) ([5aabb18](5aabb18)) * **content-gate:** institution management ui ([#4582](#4582)) ([ae88750](ae88750)) * **content-gate:** institutional access redirect and loading UX ([#4593](#4593)) ([548d236](548d236)) * **content-gate:** institutions ([#4574](#4574)) ([49b0c05](49b0c05)) * **content-gate:** personalized institutional access verification page ([#4596](#4596)) ([0eed591](0eed591)) * **image-upload:** simplify component to use basecontrol; remove info prop ([#4580](#4580)) ([d51eb54](d51eb54)) * **integrations:** add ActionScheduler group handling ([#4559](#4559)) ([411732a](411732a)) * **integrations:** promoted fields for content gate and campaign segmentation ([#4601](#4601)) ([f943df2](f943df2)) * **newspack-ui:** add stack layout and color utility classes ([#4600](#4600)) ([1934067](1934067)) * **post-date:** centralize date features from theme into plugin ([#4579](#4579)) ([19f15eb](19f15eb)) * **sync:** prevent stale data on retry, improve logging and error handling ([#4562](#4562)) ([5467f34](5467f34)) * **tags:** add private tags feature ([#4507](#4507)) ([06d7711](06d7711)) * **yoast:** add primary category utility and settings toggle ([#4563](#4563)) ([4b396c3](4b396c3))
|
🎉 This PR is included in version 6.37.0-alpha.1 🎉 The release is available on GitHub release Your semantic-release bot 📦🚀 |
All Submissions:
Changes proposed in this Pull Request:
Requires Automattic/newspack-newsletters#2053. Apply access control restrictions to available newsletter subscription lists, and auto-signup users depending on the
newspack_premium_newsletters_auto_signupoption value.Also removes Registered Access options for premium newsletter gates, as these make less sense for restricting newsletter lists.
To avoid rapid roundtrip requests to the ESP and the potential race conditions that might cause, implements debouncing logic for access checks via an access check queue. When a data event occurs that might trigger a change in a user's access to premium newsletters, their user ID is added to a queue to check their access 10 minutes in the future. Future checks are scheduled via ActionScheduler if available, using WP Cron as a backup if not.
If a scheduled check already exists due to a prior action and isn't scheduled to happen within one minute, the user ID is added to the queue for that check.
If there's no scheduled check or the next check is happening imminently, a new check is scheduled for 10 minutes after the imminent check.
When the scheduled check occurs, the callback reads the queue of user IDs and performs access checks for all at once. Each user is added to or removed from premium newsletter lists based on this access check.
In this way, we avoid trying to update users' lists in real time and only perform the updates once, well after all transitional states have passed. This only applies to the auto-signup/removal mechanism. Access to lists is reflected in real time on the site, so that users can still see and sign up for premium lists manually in the gap period if desired.
Data events that trigger an access check:
This PR doesn't attempt to reconcile the scenario where a user may have previously unsubscribed from a premium list they have access to; in this PR, the user will be readded automatically if they have access at the time of the check. I'll try to implement a fix for this in a future PR as this one is getting pretty big already.
Closes NPPD-1369.
How to test the changes in this Pull Request:
For easier testing, you may want to temporarily reduce the
Premium_Newsletters::DEFAULT_DELAYandPremium_Newsletters::FUTURE_EVENT_THRESHOLDconstants for faster turnaround. I tested successfully with these set to 15 seconds and 10 seconds, respectively.Testing access checks with Active Subscription requirements:
Premium_Newsletters::DEFAULT_DELAYelapses (or manually trigger the pending ActionScheduler event).Testing access checks with email domain whitelist
#### Testing access with reader data updatesWe decided to remove this for now. Leaving the testing steps here for posterity.
~Note: this wasn't always working reliably for me, so it might need some more work. 😕 ~
foo=barwp shell, update the reader data for the user:Newspack\Reader_Data::update_item( $user_id, 'foo', 'bar' )Testing access with institutional access
Note: I didn't implement any auto-signup or removal features for institutional access, since it feels kind of invasive to do so on something like an IP check.
/institutional-accessendpoint to trigger the IP check.Other information: