Skip to content
Merged
Show file tree
Hide file tree
Changes from 12 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
197 changes: 77 additions & 120 deletions includes/content-gate/class-content-gate.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,7 @@
*/
class Content_Gate {

const GATE_CPT = 'np_memberships_gate';

/**
* The rendered gate post ID.
*
* @var int|false
*/
private static $gate_post_id = false;
const GATE_CPT = 'np_content_gate';

/**
* Whether the gate has been rendered in this execution.
Expand All @@ -39,14 +32,20 @@ class Content_Gate {
*/
private static $is_gated = false;

/**
* Valid gate post statuses.
*
* @var array
*/
public static $valid_gate_post_statuses = [ 'publish', 'draft', 'pending', 'future', 'private', 'trash' ];

/**
* Initialize hooks and filters.
*/
public static function init() {
add_action( 'init', [ __CLASS__, 'register_post_type' ] );
add_action( 'init', [ __CLASS__, 'register_meta' ] );
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' ] );
add_action( 'wp_footer', [ __CLASS__, 'render_overlay_gate' ], 1 );
Expand Down Expand Up @@ -196,6 +195,19 @@ public static function do_blocks( $content ) {
return $output;
}

/**
* Get all gate post types.
*
* @return array Array of gate post types.
*/
public static function get_gate_post_types() {
$cpts = [ self::GATE_CPT ];
if ( Memberships::is_active() ) {
$cpts[] = Memberships::GATE_CPT;
}
return $cpts;
}

/**
* Register post type for custom gate.
*/
Expand All @@ -217,7 +229,6 @@ public static function register_post_type() {
'show_in_menu' => false,
'show_in_rest' => true,
'supports' => [ 'editor', 'custom-fields', 'revisions', 'title' ],
'taxonomies' => [ 'category', 'post_tag' ],
]
);
}
Expand Down Expand Up @@ -271,14 +282,22 @@ public static function register_meta() {
],
],
],
'post_types' => [
'content_rules' => [
'type' => 'array',
'default' => [ 'post' ],
'default' => [],
'single' => true,
'show_in_rest' => [
'schema' => [
'items' => [
'type' => 'string',
'type' => 'object',
'properties' => [
'slug' => [
'type' => 'string',
],
'value' => [
'type' => 'mixed',
],
],
],
],
],
Expand Down Expand Up @@ -308,14 +327,12 @@ public static function register_meta() {
* Redirect the custom gate CPT to the Content Gating wizard
*/
public static function redirect_cpt() {
if ( ! self::is_newspack_feature_enabled() ) {
return;
}
global $pagenow;
if ( 'edit.php' === $pagenow && isset( $_GET['post_type'] ) && self::GATE_CPT === $_GET['post_type'] ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
$redirect = \admin_url( 'admin.php?page=newspack-audience#/content-gating' );

// Once the feature is fully released, this should be the default redirect.
if ( defined( 'NEWSPACK_CONTENT_GATES' ) && NEWSPACK_CONTENT_GATES ) {
$redirect = \admin_url( 'admin.php?page=newspack-audience-content-gates' );
}
\wp_safe_redirect( $redirect );
exit;
}
Expand Down Expand Up @@ -359,7 +376,7 @@ public static function enqueue_scripts() {
* Enqueue block editor assets.
*/
public static function enqueue_block_editor_assets() {
if ( self::GATE_CPT !== get_post_type() ) {
if ( ! in_array( get_post_type(), self::get_gate_post_types(), true ) ) {
return;
}
\wp_enqueue_script(
Expand All @@ -373,13 +390,7 @@ public static function enqueue_block_editor_assets() {
'newspack-content-gate',
'newspack_content_gate',
[
'has_campaigns' => class_exists( 'Newspack_Popups' ),
'edit_gate_url' => self::get_edit_gate_url(),
'plans' => Memberships::get_plans(),
'gate_plans' => Memberships::get_gate_plans( get_the_ID() ),
'edit_plan_gate_url' => Memberships::get_edit_plan_gate_url(),
'post_types' => Content_Restriction_Control::get_available_post_types(),
'access_rules' => Access_Rules::get_access_rules(),
'has_campaigns' => class_exists( 'Newspack_Popups' ),
]
);

Expand All @@ -391,15 +402,6 @@ public static function enqueue_block_editor_assets() {
);
}

/**
* Set the post ID of the custom gate.
*
* @param int $post_id Post ID.
*/
public static function set_gate_post_id( $post_id ) {
\update_option( 'newspack_memberships_gate_post_id', $post_id );
}

/**
* Get the post ID of the custom gate.
*
Expand All @@ -408,12 +410,7 @@ public static function set_gate_post_id( $post_id ) {
* @return int|false Post ID or false if not set.
*/
public static function get_gate_post_id( $post_id = null ) {
$gate_post_id = intval( self::$gate_post_id ? self::$gate_post_id : \get_option( 'newspack_memberships_gate_post_id' ) );
if ( ! $gate_post_id ) {
$gate_post_id = false;
}

$post_id = $post_id ?? get_the_ID();
$gate_post_id = Memberships::is_active() ? Memberships::get_gate_post_id( $post_id ) : Content_Restriction_Control::get_gate_post_id( $post_id );

/**
* Filters the gate post ID.
Expand Down Expand Up @@ -506,79 +503,18 @@ public static function is_post_restricted( $post_id = null ) {
return apply_filters( 'newspack_is_post_restricted', false, $post_id );
}

/**
* Get the URL for editing the custom gate.
*
* @param int|false $gate_id Gate ID.
*
* @return string
*/
public static function get_edit_gate_url( $gate_id = false ) {
$action = 'newspack_edit_content_gate';
$url = \add_query_arg( '_wpnonce', \wp_create_nonce( $action ), \admin_url( 'admin.php?action=' . $action ) );
if ( $gate_id ) {
$url = \add_query_arg( 'gate_id', $gate_id, $url );
}
return str_replace( \site_url(), '', $url );
}

/**
* Handle editing the content gate.
*/
public static function handle_edit_gate() {
if ( ! isset( $_GET['action'] ) || 'newspack_edit_content_gate' !== $_GET['action'] ) {
return;
}
if ( ! current_user_can( 'manage_options' ) ) {
return;
}
check_admin_referer( 'newspack_edit_content_gate' );

$gate_post_id = self::get_gate_post_id();
$is_primary = true;

if ( isset( $_GET['gate_post_id'] ) ) {
$gate_post_id = absint( $_GET['gate_post_id'] );
$is_primary = false;
if ( ! $gate_post_id || ! get_post( $gate_post_id ) ) {
\wp_die( esc_html( __( 'Invalid gate post ID.', 'newspack' ) ) );
}
}

if ( $gate_post_id && get_post( $gate_post_id ) ) {
// Untrash post if it's in the trash.
if ( 'trash' === get_post_status( $gate_post_id ) ) {
\wp_untrash_post( $gate_post_id );
}
// Gate found, edit it.
\wp_safe_redirect( \admin_url( 'post.php?post=' . $gate_post_id . '&action=edit' ) );
exit;
} else {
// Gate not found, create it.
$post_title = __( 'Content Gate', 'newspack' );
$gate_post_id = self::create_gate( $post_title );
if ( is_wp_error( $gate_post_id ) ) {
\wp_die( esc_html( $gate_post_id->get_error_message() ) );
}
if ( $is_primary ) {
self::set_gate_post_id( $gate_post_id );
}
\wp_safe_redirect( \admin_url( 'post.php?post=' . $gate_post_id . '&action=edit' ) );
exit;
}
}

/**
* Create a new gate post.
*
* @param string $title Optional gate title. Defaults to 'Content Gate'.
* @param string $title Optional gate title. Defaults to 'Content Gate'.
* @param string $post_type Optional post type. Defaults to self::GATE_CPT.
*/
public static function create_gate( $title = '' ) {
public static function create_gate( $title = '', $post_type = self::GATE_CPT ) {
$all_gates = self::get_gates();
$id = \wp_insert_post(
[
'post_title' => $title,
'post_type' => self::GATE_CPT,
'post_type' => $post_type,
'post_status' => 'draft',
'post_content' => '<!-- wp:paragraph --><p>' . __( 'This post is only available to members.', 'newspack' ) . '</p><!-- /wp:paragraph -->',
'meta_input' => [
Expand Down Expand Up @@ -879,13 +815,13 @@ public static function update_gate_settings( $id, $gate ) {
return new \WP_Error( 'newspack_content_gate_not_found', __( 'Gate not found.', 'newspack' ) );
}

// Update title and description.
// Update title, priority, and status.
wp_update_post(
[
'ID' => $id,
'post_title' => $gate['title'],
'post_excerpt' => $gate['description'],
'meta_input' => [
'ID' => $id,
'post_title' => $gate['title'],
'post_status' => isset( $gate['status'] ) ? $gate['status'] : $post->post_status,
'meta_input' => [
'gate_priority' => $gate['priority'],
],
]
Expand All @@ -903,24 +839,45 @@ public static function update_gate_settings( $id, $gate ) {
return self::get_gate( $id );
}

/**
* Get the valid gate post statuses.
*
* @return array
*/
public static function get_post_statuses() {
/**
* Filters the valid post statuses for content gates.
*
* @param array $valid_post_statuses Valid gate post statuses.
*/
return apply_filters( 'newspack_content_gate_valid_post_statuses', self::$valid_gate_post_statuses );
}

/**
* Get all gates.
*
* @param string $post_type Post type.
* @param string|string[] $post_status Post status or array of statuses to fetch.
*
* @return array Array of content gates.
*/
public static function get_gates() {
public static function get_gates( $post_type = self::GATE_CPT, $post_status = null ) {
$posts = get_posts(
[
'post_type' => self::GATE_CPT,
'post_status' => [ 'publish', 'draft', 'trash', 'pending', 'future' ],
'post_type' => $post_type,
'post_status' => $post_status ? $post_status : self::get_post_statuses(),
'posts_per_page' => -1,
]
);
$gates = array_map( [ __CLASS__, 'get_gate' ], wp_list_pluck( $posts, 'ID' ) );
usort(
$gates,
function( $a, $b ) {
return $a['priority'] <=> $b['priority'];
}
);
if ( $post_type === self::GATE_CPT ) {
usort(
$gates,
function( $a, $b ) {
return $a['priority'] <=> $b['priority'];
}
);
}
return $gates;
}
}
Expand Down
27 changes: 17 additions & 10 deletions includes/content-gate/class-content-restriction-control.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ class Content_Restriction_Control {
*/
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 @@ -106,7 +105,7 @@ public static function get_post_gates( $post_id = null ) {
return [];
}

$gates = Content_Gate::get_gates();
$gates = Content_Gate::get_gates( Content_Gate::GATE_CPT, 'publish' );
if ( empty( $gates ) ) {
return [];
}
Expand All @@ -122,9 +121,10 @@ public static function get_post_gates( $post_id = null ) {
}

foreach ( $content_rules as $content_rule ) {
$is_exclusion = isset( $content_rule['exclusion'] ) && $content_rule['exclusion'];
if ( $content_rule['slug'] === 'post_types' ) {
$post_type = get_post_type( $post_id );
if ( ! in_array( $post_type, $content_rule['value'], true ) ) {
if ( $is_exclusion ? in_array( $post_type, $content_rule['value'], true ) : ! in_array( $post_type, $content_rule['value'], true ) ) {
continue 2;
}
} else {
Expand All @@ -133,10 +133,10 @@ public static function get_post_gates( $post_id = null ) {
continue 2;
}
$terms = wp_get_post_terms( $post_id, $content_rule['slug'], [ 'fields' => 'ids' ] );
if ( ! $terms || is_wp_error( $terms ) ) {
if ( ( ! $is_exclusion && ! $terms ) || is_wp_error( $terms ) ) {
continue 2;
}
if ( empty( array_intersect( $terms, $content_rule['value'] ) ) ) {
if ( $is_exclusion ? ! empty( array_intersect( $terms, $content_rule['value'] ) ) : empty( array_intersect( $terms, $content_rule['value'] ) ) ) {
continue 2;
}
}
Expand Down Expand Up @@ -193,17 +193,24 @@ public static function is_post_restricted( $is_post_restricted, $post_id = null
/**
* Get the current gate post ID.
*
* @param int $gate_post_id Gate post ID.
* @param int $post_id Post ID. If not given, uses the current post ID.
* @param int $post_id Post ID. If not given, uses the current post ID.
*
* @return int|false
*/
public static function get_gate_post_id( $gate_post_id, $post_id = null ) {
$post_id = $post_id ?? \get_the_ID();
public static function get_gate_post_id( $post_id = null ) {
if ( ! Content_Gate::is_newspack_feature_enabled() ) {
return false;
}
if ( is_singular() ) {
$post_id = $post_id ? $post_id : get_queried_object_id();
}
if ( ! $post_id ) {
return false;
}
if ( ! empty( self::$post_gate_id_map[ $post_id ] ) ) {
return self::$post_gate_id_map[ $post_id ];
}
return $gate_post_id;
return false;
}
}
Content_Restriction_Control::init();
Loading