Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions includes/class-newspack.php
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,10 @@ private function includes() {
include_once NEWSPACK_ABSPATH . 'includes/reader-activation/sync/class-woocommerce.php';
include_once NEWSPACK_ABSPATH . 'includes/reader-activation/sync/class-esp-sync.php';
include_once NEWSPACK_ABSPATH . 'includes/reader-activation/sync/class-esp-sync-admin.php';
include_once NEWSPACK_ABSPATH . 'includes/reader-activation/sync/class-integrations-init.php';
\Newspack\Reader_Activation\Sync\Integrations_Init::init();

include_once NEWSPACK_ABSPATH . 'includes/reader-activation/wisepops/class-wisepops.php';
include_once NEWSPACK_ABSPATH . 'includes/data-events/class-utils.php';
include_once NEWSPACK_ABSPATH . 'includes/data-events/class-data-events.php';
include_once NEWSPACK_ABSPATH . 'includes/data-events/class-webhooks.php';
Expand Down Expand Up @@ -125,6 +129,7 @@ private function includes() {
include_once NEWSPACK_ABSPATH . 'includes/class-syndication.php';
include_once NEWSPACK_ABSPATH . 'includes/bylines/class-bylines.php';
include_once NEWSPACK_ABSPATH . 'includes/lite-site/class-lite-site.php';
include_once NEWSPACK_ABSPATH . 'includes/content-gate/class-content-gate.php';

include_once NEWSPACK_ABSPATH . 'includes/starter_content/class-starter-content-provider.php';
include_once NEWSPACK_ABSPATH . 'includes/starter_content/class-starter-content-generated.php';
Expand Down Expand Up @@ -163,6 +168,7 @@ private function includes() {
include_once NEWSPACK_ABSPATH . 'includes/wizards/audience/class-audience-campaigns.php';
include_once NEWSPACK_ABSPATH . 'includes/wizards/audience/class-audience-donations.php';
include_once NEWSPACK_ABSPATH . 'includes/wizards/audience/class-audience-subscriptions.php';
include_once NEWSPACK_ABSPATH . 'includes/wizards/audience/class-audience-integrations.php';

// Network Wizard.
include_once NEWSPACK_ABSPATH . 'includes/wizards/class-network-wizard.php';
Expand Down
1 change: 1 addition & 0 deletions includes/class-wizards.php
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ public static function init_wizards() {
'audience' => new Audience_Wizard(),
'audience-campaigns' => new Audience_Campaigns(),
'audience-donations' => new Audience_Donations(),
'audience-integrations' => new Audience_Integrations(),
'listings' => new Listings_Wizard(),
'network' => new Network_Wizard(),
'newsletters' => new Newsletters_Wizard(),
Expand Down
155 changes: 155 additions & 0 deletions includes/content-gate/class-access-rules.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
<?php
/**
* Newspack Restricted Content Access Rules
*
* @package Newspack
*/

namespace Newspack;

use Newspack\Reader_Activation;
use Newspack\WooCommerce_Connection;

/**
* Main class.
*/
class Access_Rules {

const META_KEY = 'access_rules';

/**
* Get the available access rules.
*
* @return array
*/
public static function get_access_rules_config() {
$access_rules_config = [
'registration' => [
'name' => 'Is Registered',
'description' => 'The user must be logged into a reader account.',
'type' => 'boolean',
'default' => false,
'callback' => [ __CLASS__, 'is_registered' ],
'conflicts' => [ 'subscription' ],
],
'subscription' => [
'name' => 'Has Active Subscription',
'description' => 'The user must be logged into a reader account and have an active subscription with one of the selected products.',
'type' => 'array',
'default' => [],
'callback' => [ __CLASS__, 'has_active_subscription' ],
'conflicts' => [ 'registration' ],
],
'email_domain' => [
'name' => 'Has Whitelisted Email Domain',
'description' => 'The user must be logged into a reader account whose email address contains one of these domains. Specify multiple domains by separating them with a comma or line break.',
'type' => 'string',
'placeholder' => 'example.com,another.com',
'default' => '',
'callback' => [ __CLASS__, 'is_email_domain_whitelisted' ],
],
];

return apply_filters( 'newspack_content_gate_access_rules', $access_rules_config );
}

/**
* Get an access rule by slug.
*
* @param string $slug Access rule slug.
* @return array|null Access rule config or null if not found.
*/
public static function get_access_rule_config( $slug ) {
$access_rules = self::get_access_rules_config();
return $access_rules[ $slug ] ?? null;
}

/**
* Get access rules for bypassing a content gate.
*
* @param int $post_id Post ID.
* @return string[] Array of access rule slugs.
*/
public static function get_access_rules_for_post( $post_id ) {
$access_rules = \get_post_meta( $post_id, self::META_KEY, true );
return $access_rules ?? [];
}

/**
* Evaluate whether the given or current user can bypass the given access rule.
*
* @param string $access_rule Access rule slug.
* @param mixed $args Additional arguments for the access rule callback.
* @param int|null $user_id User ID. If not given, checks the current user.
* @return bool
*/
public static function evaluate_access_rule( $access_rule, $args = null, $user_id = null ) {
$access_rule_config = self::get_access_rule_config( $access_rule );

// Rule doesn't exist or lacks a callback function to execute, don't block access for it.
if ( empty( $access_rule_config['callback'] ) ) {
return true;
}

// If evaluating for the current user, they must be logged in.
$user_id = $user_id ?? \get_current_user_id();
if ( ! $user_id ) {
return false;
}

// Access rule must have a callable callback function.
$access_rule_callback = $access_rule_config['callback'];
if ( ! is_callable( $access_rule_callback ) ) {
return false;
}
return call_user_func( $access_rule_callback, $user_id, $args );
}

/**
* Whether the user is logged into a registered reader account.
*
* @param int $user_id User ID.
* @return bool
*/
public static function is_registered( $user_id ) {
return Reader_Activation::is_user_reader( \get_userdata( $user_id ), true );
}

/**
* Whether the user has an active subscription for one of the given products.
*
* @param int $user_id User ID.
* @param array $product_ids Required product IDs.
* @return bool
*/
public static function has_active_subscription( $user_id, $product_ids ) {
return ! empty( WooCommerce_Connection::get_active_subscriptions_for_user( $user_id, $product_ids ) );
}

/**
* Whether the user’s email address contains one of the given domains.
*
* @param int $user_id User ID.
* @param string $domains Comma-delimited list of domains.
* @return bool
*/
public static function is_email_domain_whitelisted( $user_id, $domains ) {
// If no domains are specified, allow access.
if ( empty( $domains ) ) {
return true;
}
$domains = str_replace( PHP_EOL, ',', $domains );
$domains = explode( ',', $domains );
$domains = array_map( 'trim', $domains );
$user = \get_userdata( $user_id );
if ( ! $user ) {
return false;
}
$email = $user->data->user_email;
if ( ! $email ) {
return false;
}
$email_domain = substr( $email, strrpos( $email, '@' ) + 1 );
return in_array( $email_domain, $domains, true );
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* @package Newspack
*/

namespace Newspack\Memberships;
namespace Newspack\Content_Gate;

/**
* WooCommerce Memberships Block Patterns class.
Expand All @@ -24,18 +24,17 @@ public static function init() {
* Enqueue styles.
*/
public static function enqueue_styles() {
$should_enqueue_styles = class_exists( 'WC_Memberships' );
/**
* Filters whether to enqueue the reader auth scripts.
*
* @param bool $should_enqueue_styles Whether to enqueue the reader auth scripts.
*/
if ( ! apply_filters( 'newspack_enqueue_memberships_block_patterns', $should_enqueue_styles ) ) {
if ( ! apply_filters( 'newspack_enqueue_content_gate_block_patterns', true ) ) {
return false;
}
wp_enqueue_style(
'newspack-memberships-block-patterns',
\Newspack\Newspack::plugin_url() . '/dist/memberships-gate-block-patterns.css',
'newspack-content_gate-block-patterns',
\Newspack\Newspack::plugin_url() . '/dist/content-gate-block-patterns.css',
[],
NEWSPACK_PLUGIN_VERSION
);
Expand Down Expand Up @@ -69,11 +68,7 @@ public static function get_block_patterns() {
* Register block patterns.
*/
public static function register_block_patterns() {
// Bail if Woo Memberships is not active.
if ( ! class_exists( 'WC_Memberships' ) ) {
return false;
}
\register_block_pattern_category( 'newspack-memberships', [ 'label' => __( 'Newspack Memberships', 'newspack' ) ] );
\register_block_pattern_category( 'newspack-content-gate', [ 'label' => __( 'Newspack Content Gate', 'newspack' ) ] );
$patterns = self::get_block_patterns();
foreach ( $patterns as $slug => $title ) {
$path = __DIR__ . '/block-patterns/' . $slug . '.php';
Expand All @@ -87,9 +82,9 @@ public static function register_block_patterns() {
continue;
}
\register_block_pattern(
'newspack-memberships/' . $slug,
'newspack-content-gate/' . $slug,
[
'categories' => [ 'newspack-memberships' ],
'categories' => [ 'newspack-content-gate' ],
'title' => $title,
'description' => _x( 'Invite your reader to become a member before continuing reading the article', 'Block pattern description', 'newspack' ),
'content' => $content,
Expand Down
Loading