Skip to content

Conversation

@chickenn00dle
Copy link
Contributor

@chickenn00dle chickenn00dle commented Sep 10, 2025

All Submissions:

Changes proposed in this Pull Request:

Closes https://linear.app/a8c/issue/NPPM-2204/content-restriction-block-shows-countdown-before-you-hit-the-wall-you

This PR adds a new content gate countdown block that displays the remaining free metered views for a post or page:

Screenshot 2025-09-15 at 19 45 53

How to test the changes in this Pull Request:

  1. First create some memberships and have some readers that are members and non-members
  2. Create some content gates for these memberships, making sure each has metering active
  3. Add the content gate countdown block to several of the restricted posts/pages in which the block has been added
  4. Test that the block
  • appears on the frontend when within the metered view limit
  • countsdown as the reader views more relevant content
  • appears on the frontend for posts that have already been viewed when the limit is reached
  • does not appear on the frontend for newly viewed posts whenever the limit is reached (gate should be displayed instead)
  • does not appear for members who have access
  • Be sure to also test the for logged in members, logged in non-members, and logged out readers

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?

@chickenn00dle chickenn00dle force-pushed the feat/add-content-gate-countdown-block branch 3 times, most recently from c4c29f2 to d4b8352 Compare September 11, 2025 22:11
@chickenn00dle chickenn00dle force-pushed the feat/add-content-gate-countdown-block branch 3 times, most recently from 0ce4d23 to 61ec477 Compare September 15, 2025 23:44
@chickenn00dle chickenn00dle marked this pull request as ready for review September 15, 2025 23:45
@chickenn00dle chickenn00dle requested a review from a team as a code owner September 15, 2025 23:45
@chickenn00dle chickenn00dle added [Status] Needs Review The issue or pull request needs to be reviewed and removed [Status] Needs Review The issue or pull request needs to be reviewed labels Sep 15, 2025
@chickenn00dle chickenn00dle force-pushed the feat/add-content-gate-countdown-block branch from 28ca464 to c28dd18 Compare September 16, 2025 17:37
$regex = "$category\/$name";
}
$content = preg_replace( "/<!-- wp:$regex {?.*?}? -->.*?<!-- \/wp:$regex -->/s", '', $content );
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

If we don't filter this, any inner paragraph blocks within the content gate block will appear in the excerpt despite us explicitly returning an empty string in the render callback.

'newspack-blocks/checkout-button',
{
text: __( 'Subscribe now', 'newspack-plugin' ),
align: 'center',
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Note, alignment is broken in the editor right now and will be fixed in Automattic/newspack-blocks#2207

@chickenn00dle chickenn00dle added the [Status] Needs Review The issue or pull request needs to be reviewed label Sep 16, 2025
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR introduces a new content gate countdown block that displays remaining free metered views for a post or page. The block allows readers to see how many free articles they have left before hitting their metering limit.

  • Adds a new WordPress block called "Content Gate Countdown" for the Newspack plugin
  • Implements frontend JavaScript functionality to dynamically update countdown for anonymous users
  • Integrates with existing metering system to display current usage against total allowed views

Reviewed Changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
webpack.config.js Adds build entry for the new countdown block's frontend view script
src/blocks/index.js Registers the new countdown block with conditional loading based on membership availability
src/blocks/content-gate-countdown/view.js Frontend JavaScript that updates countdown display for anonymous users
src/blocks/content-gate-countdown/style.scss CSS styling for the countdown block's responsive layout
src/blocks/content-gate-countdown/index.js Block registration with metadata, settings, and save function
src/blocks/content-gate-countdown/edit.jsx Block editor component with inspector controls and preview functionality
src/blocks/content-gate-countdown/class-content-gate-countdown-block.php PHP class handling block registration, rendering, and server-side logic
src/blocks/content-gate-countdown/block.json Block metadata defining attributes and supported features
packages/icons/src/content-gate-countdown.js SVG icon component for the countdown block
packages/icons/index.js Exports the new countdown icon
includes/plugins/wc-memberships/class-metering.php Adds utility methods for retrieving metering data
includes/plugins/wc-memberships/class-memberships.php Excludes countdown block from post excerpts
includes/class-blocks.php Includes countdown block class and provides metering data to editor

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

Copy link
Member

@miguelpeixe miguelpeixe left a comment

Choose a reason for hiding this comment

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

It's working mostly well! I encountered a few issues and suggestions that I commented inline.

Comment on lines 66 to 73
<Placeholder
icon={ caution }
label={ __(
'The content gate countdown block will only display in restricted content when metering is enabled.',
'newspack-plugin'
) }
className="no-metering"
/>
Copy link
Member

Choose a reason for hiding this comment

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

This should also have blockProps, otherwise the element won't interact well with the editor.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added in c9ed5ab

Comment on lines 10 to 13
use Newspack;
use Newspack\Memberships;
use Newspack\Memberships\Metering;
Copy link
Member

Choose a reason for hiding this comment

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

Can we namespace this to Newspack instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good call. Changed in c9ed5ab

Comment on lines +13 to +14
use Newspack\Memberships;
use Newspack\Memberships\Metering;
Copy link
Member

@miguelpeixe miguelpeixe Sep 18, 2025

Choose a reason for hiding this comment

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

This is superfluous as we're already in the Newspack namespace.

We can keep Newspack\Memberships\Metering, but I don't think it's bad to use Memberships\Metering in the code.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It feels cleaner to use just Metering in the code imo, so I'll keep it as is. Happy to change it if you feel strongly about it though!

Comment on lines 71 to 74
if ( ! Metering::is_metering() ) {
return '';
}
Copy link
Member

Choose a reason for hiding this comment

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

I think we also need to bail on ! Memberships::is_post_restricted(), otherwise the block will render for readers with access.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah. Good catch! I had removed this part of the check while working on styles and forgot to re-add it before submitting for review. Fixed in c9ed5ab

$countdown = sprintf(
/* translators: 1: remaining metered views, 2: total metered views. */
__( '%1$d/%2$d', 'newspack-plugin' ),
max( 0, $total_views - $remaining_views ),
Copy link
Member

Choose a reason for hiding this comment

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

The amount was already calculated here. It's going full circle and returning the number of articles read 😄

Speaking of which, even though I'm aware that the block is called countdown, reading 4/5 on my first visit was a bit odd. Not sure if it's because of the way it's phrased, maybe it's just me. @thomasguillot can you confirm whether it should be the number of articles read or remaining?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The amount was already calculated here. It's going full circle and returning the number of articles read 😄

Ha. Yeah. I initially had this counting down using the remaining count. Then at the last second I thought it made more sense to show the number of articles read and made this change. I've gone back to remaining count here in c9ed5ab, but I'd like to get confirmation from @thomasguillot as well to know what this number should be.

Copy link
Contributor

Choose a reason for hiding this comment

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

It's meant to be 4 articles read out of 5. So the first visit should be 1/5

Copy link
Contributor

Choose a reason for hiding this comment

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

So you have read 1 article. And you have 5 free.

Copy link
Contributor

Choose a reason for hiding this comment

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

And not read 4 articles

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks @thomasguillot! Updated this to count up in 68df86c

"default": ""
}
},
"supports": {
Copy link
Member

Choose a reason for hiding this comment

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

Looking at the design, it seems that the block should also support align, so it can also render wide and full width.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good catch! Added in c9ed5ab

},
],
[
'newspack-blocks/checkout-button',
Copy link
Member

Choose a reason for hiding this comment

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

WDYT of adding "backgroundColor":"primary" to the template as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure thing! This requires setting textColor to secondary to avoid contrast issues. Added in c9ed5ab

Comment on lines +57 to +60
// Admin is always logged in, so if no loggedin metered views are set, use the anonymous views instead.
const totalViews = loggedinViews > 0 ? loggedinViews : anonymousViews;
Copy link
Member

Choose a reason for hiding this comment

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

This is a bit confusing. Isn't this about whether the post gate has metering configured?

Something like:

Suggested change
// Admin is always logged in, so if no loggedin metered views are set, use the anonymous views instead.
const totalViews = loggedinViews > 0 ? loggedinViews : anonymousViews;
const hasMetering = loggedinViews || anonymousViews;

Still, this does not take into account whether metering is active (the metering meta)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The problem this is solving is in the editor, the user (admin) is always logged in, so if the post is metered for anonymous readers and not registered readers, then the views will always be 0 in the editor.

I named this variable totalViews because below we use it when displaying the countdown: https://github.com/Automattic/newspack-plugin/pull/4176/files/d116d5625454735dbf6c024e91b43626c93b6705#diff-da1ae48178cfb1fb24cf269739fc3d32517200fb0105cefdba1155dba8c45f9eR98

As for using the || operator instead of the ternary, I thought the ternary made it a bit clearer that we are falling back to anonymous views if loggedin views was 0. But both will have the same result, so happy to change it if you prefer!

Still, this does not take into account whether metering is active (the metering meta)

Yeah. I decided not to check the meta here because having both loggedinViews and anonymousViews be 0 is effectively the same as not having metering active.

@github-actions github-actions bot added the [Status] Needs Changes or Feedback The issue or pull request needs action from the original creator label Sep 18, 2025
@chickenn00dle chickenn00dle force-pushed the feat/add-content-gate-countdown-block branch from c9ed5ab to 009cbde Compare September 19, 2025 14:36
@chickenn00dle chickenn00dle removed the [Status] Needs Changes or Feedback The issue or pull request needs action from the original creator label Sep 23, 2025
Copy link
Member

@miguelpeixe miguelpeixe left a comment

Choose a reason for hiding this comment

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

Thank you for the revisions! It's working great, but I found a couple of issues:

Comment on lines +31 to +37
// Replace countdown for anonymous users.
const countdown = sprintf(
/* translators: 1: current number of metered views, 2: total metered views. */ __( '%1$d/%2$d', 'newspack-plugin' ),
content.length,
count
);
countdownEl.textContent = countdown;
Copy link
Member

Choose a reason for hiding this comment

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

When accessing an article for the first time with anonymous metering, I'm getting 0 reads:

Image

We may need to listen to the metering_restricted activity dispatch for an accurate number here

Copy link
Contributor Author

@chickenn00dle chickenn00dle Sep 24, 2025

Choose a reason for hiding this comment

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

Strange, on my end the metering script is always run before the countdown script, and the value is correctly updated:
Screenshot 2025-09-24 at 16 55 59

I checked in multiple browsers to confirm this isn't some browser loading order quirk. In any case, I added the metering script handle as a dependency when enqueuing the countdown script to ensure this is always the case in 4202b80

}
wp_enqueue_style(
'newspack-content-gate-countdown-block',
\Newspack\Newspack::plugin_url() . '/dist/content-gate-countdown-block.css',
Copy link
Member

Choose a reason for hiding this comment

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

Not sure why, but I'm getting 404 for this asset.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Looks like the styles for this are being bundled into commons by webpack. Not sure if this is what you are seeing. On my end, there is no content-gate-countdown-block.css being fetched. Instead the styles live in commons.css

Copy link
Member

Choose a reason for hiding this comment

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

It's getting added to the markup and throwing 404:

image

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah sorry! Seeing it now. I guess we don't need to enqueue the styles here 🤷‍♂️

@github-actions github-actions bot added the [Status] Needs Changes or Feedback The issue or pull request needs action from the original creator label Sep 24, 2025
@github-actions github-actions bot added [Status] Approved The pull request has been reviewed and is ready to merge and removed [Status] Needs Review The issue or pull request needs to be reviewed [Status] Needs Changes or Feedback The issue or pull request needs action from the original creator labels Sep 25, 2025
@chickenn00dle chickenn00dle merged commit f8fe757 into trunk Sep 25, 2025
11 checks passed
@chickenn00dle chickenn00dle deleted the feat/add-content-gate-countdown-block branch September 25, 2025 15:43
@github-actions
Copy link

Hey @chickenn00dle, 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 Sep 25, 2025
# [6.20.0-alpha.1](v6.19.0...v6.20.0-alpha.1) (2025-09-25)

### Bug Fixes

* Improve help text for Guest Contributor checkbox ([#4187](#4187)) ([5790f3d](5790f3d))
* newspack-plugin delay ([#4184](#4184)) ([22e8dc2](22e8dc2))
* update download URL for db.php ([#4193](#4193)) ([4d363db](4d363db))

### Features

* **collections:** add Collections block ([#4166](#4166)) ([1185157](1185157))
* **collections:** add logic for opening links in new tabs ([#4174](#4174)) ([07a5545](07a5545))
* **collections:** collections block feedback ([#4185](#4185)) ([0d0210c](0d0210c))
* **collections:** remove feature flag ([#4195](#4195)) ([b1619ef](b1619ef))
* **collections:** replace archive grid with collections block ([#4178](#4178)) ([d0cbadd](d0cbadd))
* **content-gate:** add countdown block ([#4176](#4176)) ([f8fe757](f8fe757))
* **my-account:** subscription switch modal ([#4177](#4177)) ([28c26e7](28c26e7))
* subscription tier modal ([#4164](#4164)) ([4d6ebe2](4d6ebe2))
@matticbot
Copy link
Contributor

🎉 This PR is included in version 6.20.0-alpha.1 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

chickenn00dle added a commit that referenced this pull request Sep 29, 2025
matticbot pushed a commit that referenced this pull request Oct 6, 2025
# [6.20.0](v6.19.0...v6.20.0) (2025-10-06)

### Bug Fixes

* ga4 events for gate interactions and tiered modal ([#4209](#4209)) ([2d35768](2d35768))
* Improve help text for Guest Contributor checkbox ([#4187](#4187)) ([5790f3d](5790f3d))
* newspack-plugin delay ([#4184](#4184)) ([22e8dc2](22e8dc2))
* remove content gate countdown block ([0204e58](0204e58))
* update download URL for db.php ([#4193](#4193)) ([4d363db](4d363db))

### Features

* **collections:** add archive link in settings page ([#4203](#4203)) ([42694ec](42694ec))
* **collections:** add Collections block ([#4166](#4166)) ([1185157](1185157))
* **collections:** add css classes to meta elements ([#4208](#4208)) ([7fbf7e9](7fbf7e9))
* **collections:** add logic for opening links in new tabs ([#4174](#4174)) ([07a5545](07a5545))
* **collections:** collections block feedback ([#4185](#4185)) ([0d0210c](0d0210c))
* **collections:** remove feature flag ([#4195](#4195)) ([b1619ef](b1619ef))
* **collections:** replace archive grid with collections block ([#4178](#4178)) ([d0cbadd](d0cbadd))
* **content-gate:** add countdown block ([#4176](#4176)) ([f8fe757](f8fe757))
* **my-account:** subscription switch modal ([#4177](#4177)) ([28c26e7](28c26e7))
* subscription tier modal ([#4164](#4164)) ([4d6ebe2](4d6ebe2))
@matticbot
Copy link
Contributor

🎉 This PR is included in version 6.20.0 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

released on @alpha released [Status] Approved The pull request has been reviewed and is ready to merge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants