diff --git a/includes/class-blocks.php b/includes/class-blocks.php index 4a2adf28a9..4a3be8e3f8 100644 --- a/includes/class-blocks.php +++ b/includes/class-blocks.php @@ -10,6 +10,8 @@ defined( 'ABSPATH' ) || exit; use Newspack\Optional_Modules\Collections; +use Newspack\Memberships; +use Newspack\Memberships\Metering; /** * Newspack Blocks Class. @@ -20,6 +22,7 @@ final class Blocks { */ public static function init() { require_once NEWSPACK_ABSPATH . 'src/blocks/reader-registration/index.php'; + require_once NEWSPACK_ABSPATH . 'src/blocks/content-gate-countdown/class-content-gate-countdown-block.php'; if ( wp_is_block_theme() && class_exists( 'Newspack\Corrections' ) ) { require_once NEWSPACK_ABSPATH . 'src/blocks/correction-box/class-correction-box-block.php'; @@ -49,22 +52,32 @@ public static function enqueue_block_editor_assets() { NEWSPACK_PLUGIN_VERSION, true ); + $script_data = [ + 'has_newsletters' => class_exists( 'Newspack_Newsletters_Subscription' ), + 'has_reader_activation' => Reader_Activation::is_enabled(), + 'newsletters_url' => Wizards::get_wizard( 'newsletters' )->newsletters_settings_url(), + 'has_google_oauth' => Google_OAuth::is_oauth_configured(), + 'google_logo_svg' => \Newspack\Newspack_UI_Icons::get_svg( 'google' ), + 'reader_activation_terms' => Reader_Activation::get_setting( 'terms_text' ), + 'reader_activation_url' => Reader_Activation::get_setting( 'terms_url' ), + 'has_recaptcha' => Recaptcha::can_use_captcha(), + 'recaptcha_url' => admin_url( 'admin.php?page=newspack-settings' ), + 'corrections_enabled' => wp_is_block_theme() && class_exists( 'Newspack\Corrections' ), + 'collections_enabled' => Collections::is_module_active(), + 'has_memberships' => Memberships::is_active(), + ]; + if ( $script_data['has_memberships'] ) { + $script_data['content_gate_data'] = [ + 'anonymous_metered_views' => Metering::get_total_metered_views( false ), + 'loggedin_metered_views' => Metering::get_total_metered_views( true ), + 'metered_views' => Metering::get_metered_views(), + 'metering_period' => Metering::get_metering_period(), + ]; + } \wp_localize_script( 'newspack-blocks', 'newspack_blocks', - [ - 'has_newsletters' => class_exists( 'Newspack_Newsletters_Subscription' ), - 'has_reader_activation' => Reader_Activation::is_enabled(), - 'newsletters_url' => Wizards::get_wizard( 'newsletters' )->newsletters_settings_url(), - 'has_google_oauth' => Google_OAuth::is_oauth_configured(), - 'google_logo_svg' => \Newspack\Newspack_UI_Icons::get_svg( 'google' ), - 'reader_activation_terms' => Reader_Activation::get_setting( 'terms_text' ), - 'reader_activation_url' => Reader_Activation::get_setting( 'terms_url' ), - 'has_recaptcha' => Recaptcha::can_use_captcha(), - 'recaptcha_url' => admin_url( 'admin.php?page=newspack-settings' ), - 'corrections_enabled' => wp_is_block_theme() && class_exists( 'Newspack\Corrections' ), - 'collections_enabled' => Collections::is_module_active(), - ] + $script_data ); \wp_enqueue_style( 'newspack-blocks', diff --git a/includes/plugins/wc-memberships/class-memberships.php b/includes/plugins/wc-memberships/class-memberships.php index 6434f4a3d8..a0e1315eea 100644 --- a/includes/plugins/wc-memberships/class-memberships.php +++ b/includes/plugins/wc-memberships/class-memberships.php @@ -686,6 +686,29 @@ public static function get_restricted_post_excerpt( $post ) { $content = explode( '', $content )[0]; } else { $count = (int) get_post_meta( $gate_post_id, 'visible_paragraphs', true ); + // Remove all spaces. + $content = preg_replace( '/\s+/', ' ', $content ); + /** + * Filter the list of blocks to exclude from the excerpt. + * + * @param array $excluded_blocks Array of blocks to exclude. i.e. [ 'core/image', 'newspack/content-gate-countdown' ]. + * + * @return array + */ + $excluded_blocks = apply_filters( 'newspack_memberships_excerpt_excluded_blocks', [ 'newspack/content-gate-countdown' ] ); + // Remove unwanted blocks from the content. + foreach ( $excluded_blocks as $block ) { + [ $category, $name ] = explode( '/', $block ); + if ( ! $category || ! $name ) { + continue; + } + if ( 'core' === $category ) { + $regex = $name; + } else { + $regex = "$category\/$name"; + } + $content = preg_replace( "/.*?/s", '', $content ); + } // Split into paragraphs. $content = explode( '
', $content ); // Extract the first $x paragraphs only. diff --git a/includes/plugins/wc-memberships/class-metering.php b/includes/plugins/wc-memberships/class-metering.php index f5049e1451..25826e9310 100644 --- a/includes/plugins/wc-memberships/class-metering.php +++ b/includes/plugins/wc-memberships/class-metering.php @@ -298,5 +298,65 @@ public static function get_article_view( $activity ) { self::$article_view = $activity; return $activity; } + + /** + * Get the metering period for a post. + * + * @param int|null $post_id Post ID. Default is current post. + * + * @return string Metered period (day, week, month). + */ + public static function get_metering_period( $post_id = null ) { + if ( ! $post_id ) { + $post_id = get_the_ID(); + } + $gate_post_id = Memberships::get_gate_post_id( $post_id ); + return \get_post_meta( $gate_post_id, 'metering_period', true ); + } + + /** + * Get number of metered views for the user. + * + * @param int|null $user_id User ID. Default is current user. + * + * @return int Number of metered views. + */ + public static function get_metered_views( $user_id = null ) { + if ( ! $user_id ) { + $user_id = get_current_user_id(); + } + // For anonymous users, return the anonymous count. + if ( ! $user_id ) { + $gate_post_id = Memberships::get_gate_post_id(); + return (int) \get_post_meta( $gate_post_id, 'metering_anonymous_count', true ); + } + + // For logged-in users, calculate the remaining views based on their metering data. + $gate_post_id = Memberships::get_gate_post_id(); + $user_meta_key = self::METERING_META_KEY . '_' . $gate_post_id; + $user_metering_data = \get_user_meta( $user_id, $user_meta_key, true ); + if ( ! is_array( $user_metering_data ) || ! isset( $user_metering_data['content'] ) ) { + return $count; + } + return count( $user_metering_data['content'] ); + } + + /** + * Get total number of metered views for current post. + * + * @param boolean $is_logged_in Whether to check for logged-in or anonymous users. Default is false (anonymous). + * + * @return int|boolean Total number of metered views if metering is enabled, otherwise false. + */ + public static function get_total_metered_views( $is_logged_in = false ) { + $gate_post_id = Memberships::get_gate_post_id( get_the_ID() ); + if ( ! $gate_post_id ) { + return false; + } + if ( ! $is_logged_in ) { + return (int) \get_post_meta( $gate_post_id, 'metering_anonymous_count', true ); + } + return (int) \get_post_meta( $gate_post_id, 'metering_registered_count', true ); + } } Metering::init(); diff --git a/packages/icons/index.js b/packages/icons/index.js index b7819aec75..296fdf4311 100644 --- a/packages/icons/index.js +++ b/packages/icons/index.js @@ -33,3 +33,4 @@ export { default as searchEmpty } from './src/search-empty'; export { default as tabItem } from './src/tab-item'; export { default as tabs } from './src/tabs'; export { default as theme } from './src/theme'; +export { default as countdown } from './src/content-gate-countdown'; diff --git a/packages/icons/src/content-gate-countdown.js b/packages/icons/src/content-gate-countdown.js new file mode 100644 index 0000000000..07bd8cc652 --- /dev/null +++ b/packages/icons/src/content-gate-countdown.js @@ -0,0 +1,13 @@ +/** + * WordPress dependencies + */ +import { SVG, Path } from '@wordpress/primitives'; + +const countdown = ( + +); + +export default countdown; diff --git a/src/blocks/content-gate-countdown/block.json b/src/blocks/content-gate-countdown/block.json new file mode 100644 index 0000000000..36f62e83ea --- /dev/null +++ b/src/blocks/content-gate-countdown/block.json @@ -0,0 +1,39 @@ +{ + "$schema": "https://schemas.wp.org/trunk/block.json", + "apiVersion": 3, + "name": "newspack/content-gate-countdown", + "category": "newspack", + "attributes": { + "text": { + "type": "string", + "default": "" + } + }, + "supports": { + "align": [ "wide", "full" ], + "html": false, + "color": { + "link": true, + "__experimentalDefaultControls": { + "background": true, + "text": true + } + }, + "typography": { + "fontSize": true, + "lineHeight": true, + "textAlign": true, + "__experimentalFontFamily": true, + "__experimentalTextDecoration": true, + "__experimentalFontStyle": true, + "__experimentalFontWeight": true, + "__experimentalLetterSpacing": true, + "__experimentalTextTransform": true, + "__experimentalWritingMode": true, + "__experimentalDefaultControls": { + "fontSize": true + } + } + }, + "textdomain": "newspack-plugin" +} diff --git a/src/blocks/content-gate-countdown/class-content-gate-countdown-block.php b/src/blocks/content-gate-countdown/class-content-gate-countdown-block.php new file mode 100644 index 0000000000..4f3ace444b --- /dev/null +++ b/src/blocks/content-gate-countdown/class-content-gate-countdown-block.php @@ -0,0 +1,110 @@ + [ __CLASS__, 'render_block' ], + ] + ); + } + + /** + * Block render callback. + * + * @param array $attributes The block attributes. + * @param string $content The block content. + * + * @return string The block HTML. + */ + public static function render_block( array $attributes, string $content ) { + if ( ! Metering::is_metering() || ! Memberships::is_post_restricted() ) { + return ''; + } + $total_views = Metering::get_total_metered_views( \is_user_logged_in() ); + if ( false === $total_views ) { + return ''; + } + $views = Metering::get_metered_views( get_current_user_id() ); + $countdown = sprintf( + /* translators: 1: current number of metered views, 2: total metered views. */ + __( '%1$d/%2$d', 'newspack-plugin' ), + $views, + $total_views + ); + $text = isset( $attributes['text'] ) ? esc_html( $attributes['text'] ) : ''; + if ( empty( $text ) ) { + $text = sprintf( + /* translators: %s - metered content period (week, month, etc. */ + __( + 'free articles this %s', + 'newspack-plugin' + ), + Metering::get_metering_period() + ); + } + $block_wrapper_attributes = get_block_wrapper_attributes( + [ + 'class' => 'newspack-content-gate-countdown__wrapper', + ] + ); + $block_content = "$text
+{ text }
+