Skip to content
Draft
34 changes: 14 additions & 20 deletions includes/content-gate/class-content-gate.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ class Content_Gate {
public static function init() {
add_action( 'init', [ __CLASS__, 'register_post_type' ] );
add_action( 'init', [ __CLASS__, 'register_meta' ] );
// Commenting out to temporarily enable CPT UI for testing: `add_action( 'admin_init', [ __CLASS__, 'redirect_cpt' ] );` !
add_action( 'admin_init', [ __CLASS__, 'redirect_cpt' ] );
add_action( 'admin_init', [ __CLASS__, 'handle_edit_gate' ] );
add_action( 'wp_enqueue_scripts', [ __CLASS__, 'enqueue_scripts' ] );
add_action( 'enqueue_block_editor_assets', [ __CLASS__, 'enqueue_block_editor_assets' ] );
Expand Down Expand Up @@ -83,10 +83,12 @@ public static function restrict_post( $post, $query ) {
if ( ! $query->is_main_query() ) {
return;
}
if ( self::has_rendered() ) {
if ( ! is_singular() ) {
return;
}
if ( get_queried_object_id() !== $post->ID ) {
return;
}

// Don't apply our restriction strategy if Woo Memberships is active.
if ( Memberships::is_active() ) {
return;
Expand All @@ -95,9 +97,6 @@ public static function restrict_post( $post, $query ) {
if ( is_admin() ) {
return;
}
if ( ! self::has_gate() ) {
return;
}
if ( ! self::is_post_restricted( $post->ID ) ) {
return;
}
Expand All @@ -117,9 +116,7 @@ public static function restrict_post( $post, $query ) {

$content = self::get_restricted_post_excerpt( $post );

$content .= self::get_inline_gate_content();

$post->post_content = $content;
$post->post_content = $content . self::get_inline_gate_content();
$post->post_excerpt = $content;
$post->comment_status = 'closed';
$post->comment_count = 0;
Expand Down Expand Up @@ -415,11 +412,13 @@ public static function get_gate_post_id( $post_id = null ) {
$gate_post_id = false;
}

$post_id = $post_id ?? get_the_ID();

/**
* Filters the gate post ID.
*
* @param int $gate_post_id Gate post ID.
* @param int $post_id Post ID.
* @param int $post_id Post ID.
*/
return apply_filters( 'newspack_content_gate_post_id', $gate_post_id, $post_id );
}
Expand Down Expand Up @@ -478,16 +477,11 @@ public static function is_post_restricted( $post_id = null ) {

/**
* Filters whether the post is restricted for the current user.
* If the post is restricted by a content gate, return the gate post ID.
*
* @param int|bool $restricted_by If restricted, the gate post ID. False if not restricted.
* @param int $post_id Post ID.
* @param bool $restricted_by Whether the post is restricted.
* @param int $post_id Post ID.
*/
$restricted_by = apply_filters( 'newspack_is_post_restricted', false, $post_id );
if ( $restricted_by && is_int( $restricted_by ) ) {
self::$gate_post_id = $restricted_by;
}
return $restricted_by;
return apply_filters( 'newspack_is_post_restricted', false, $post_id );
}

/**
Expand Down Expand Up @@ -631,7 +625,7 @@ public static function get_restricted_post_excerpt( $post ) {
$content = apply_filters( 'newspack_gate_content', explode( '<!--more-->', $content )[0] );
} else {
$content = apply_filters( 'newspack_gate_content', $content );
$count = (int) get_post_meta( $gate_post_id, 'visible_paragraphs', true );
$count = max( 1, (int) get_post_meta( $gate_post_id, 'visible_paragraphs', true ) );
// Split into paragraphs.
$content = explode( '</p>', $content );
// Extract the first $x paragraphs only.
Expand Down Expand Up @@ -735,7 +729,7 @@ public static function get_gate( $id ) {
return [
'id' => $post->ID,
'title' => $post->post_title,
'description' => $post->post_excerpt,
'status' => $post->post_status,
'metering' => Metering::get_metering_settings( $post->ID ),
'priority' => (int) get_post_meta( $post->ID, 'gate_priority', true ),
'access_rules' => Access_Rules::get_post_access_rules( $post->ID ),
Expand Down
93 changes: 69 additions & 24 deletions includes/content-gate/class-content-restriction-control.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,19 @@
* Main class.
*/
class Content_Restriction_Control {
/**
* Map of post IDs to gate IDs.
*
* @var array
*/
private static $post_gate_id_map = [];

/**
* Initialize hooks and filters.
*/
public static function init() {
add_filter( 'newspack_is_post_restricted', [ __CLASS__, 'is_post_restricted' ], 10, 2 );
add_filter( 'newspack_content_gate_post_id', [ __CLASS__, 'get_gate_post_id' ], 10, 2 );
}

/**
Expand Down Expand Up @@ -91,35 +98,52 @@ public static function get_available_taxonomies() {
*
* @param int $post_id Optional post ID.
*
* @return int[] Array of gate post IDs.
* @return array Array of post gates.
*/
public static function get_post_gates( $post_id = null ) {
$post_id = $post_id ?? \get_the_ID();
$post_type = \get_post_type( $post_id );
$categories = \wp_get_post_categories( $post_id );
$tags = \wp_get_post_tags( 2742, [ 'fields' => 'ids' ] );
$post_id = $post_id ?? \get_the_ID();
if ( ! $post_id ) {
return [];
}

$gate_post_ids = [];
$gates = Content_Gate::get_gates();
$gates = Content_Gate::get_gates();
if ( empty( $gates ) ) {
return [];
}

$post_gates = [];
foreach ( $gates as $gate ) {
$gate_post_types = \get_post_meta( $gate->ID, 'post_types', true );
$gate_categories = \wp_get_post_categories( $gate->ID );
$gate_tags = \wp_get_post_tags( $gate->ID, [ 'fields' => 'ids' ] );

if ( empty( $gate_post_types ) || ! in_array( $post_type, $gate_post_types, true ) ) {
if ( 'publish' !== $gate['status'] ) {
continue;
}
if ( ! empty( $gate_categories ) && empty( array_intersect( $gate_categories, $categories ) ) ) {
$content_rules = $gate['content_rules'];
if ( empty( $content_rules ) ) {
continue;
}
if ( ! empty( $gate_tags ) && empty( array_intersect( $gate_tags, $tags ) ) ) {
continue;

foreach ( $content_rules as $content_rule ) {
if ( $content_rule['slug'] === 'post_type' ) {
$post_type = get_post_type( $post_id );
if ( ! in_array( $post_type, $content_rule['value'], true ) ) {
continue 2;
}
} else {
$taxonomy = get_taxonomy( $content_rule['slug'] );
if ( ! $taxonomy ) {
continue 2;
}
$terms = wp_get_post_terms( $post_id, $content_rule['slug'], [ 'fields' => 'ids' ] );
if ( ! $terms || is_wp_error( $terms ) ) {
continue 2;
}
if ( empty( array_intersect( $terms, $content_rule['value'] ) ) ) {
continue 2;
}
}
}
$gate_post_ids[] = $gate->ID;
$post_gates[] = $gate;
}

return $gate_post_ids;
return $post_gates;
}

/**
Expand All @@ -141,23 +165,44 @@ public static function is_post_restricted( $is_post_restricted, $post_id = null
return $is_post_restricted;
}

$gate_ids = self::get_post_gates( $post_id );
if ( empty( $gate_ids ) ) {
$post_gates = self::get_post_gates( $post_id );
if ( empty( $post_gates ) ) {
return false;
}

foreach ( $gate_ids as $gate_id ) {
$access_rules = Access_Rules::get_post_access_rules( $gate_id );
// Return if the post gate has already been determined.
if ( ! empty( self::$post_gate_id_map[ $post_id ] ) ) {
return true;
}

foreach ( $post_gates as $gate ) {
$access_rules = $gate['access_rules'];
if ( empty( $access_rules ) ) {
continue;
}
foreach ( $access_rules as $rule ) {
if ( ! Access_Rules::evaluate_rule( $rule['slug'], $rule['value'] ?? null ) ) {
return false;
self::$post_gate_id_map[ $post_id ] = $gate['id'];
return true;
}
}
}
return true;
return false;
}

/**
* Get the current gate post ID.
*
* @param int $gate_post_id Gate post ID.
* @param int $post_id Post ID.
*
* @return int|false
*/
public static function get_gate_post_id( $gate_post_id, $post_id = null ) {
if ( ! empty( self::$post_gate_id_map[ $post_id ] ) ) {
return self::$post_gate_id_map[ $post_id ];
}
return $gate_post_id;
}
}
Content_Restriction_Control::init();