Skip to content
Merged
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
100 changes: 92 additions & 8 deletions includes/content-gate/class-content-gate.php
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ public static function init() {
add_action( 'admin_init', [ __CLASS__, 'handle_edit_gate_layout' ] );
add_action( 'wp_enqueue_scripts', [ __CLASS__, 'enqueue_scripts' ] );
add_action( 'wp_footer', [ __CLASS__, 'render_overlay_gate' ], 1 );
add_action( 'before_delete_post', [ __CLASS__, 'delete_gate_layouts' ], 10, 2 );
add_filter( 'newspack_popups_assess_has_disabled_popups', [ __CLASS__, 'disable_popups' ] );
add_filter( 'newspack_reader_activity_article_view', [ __CLASS__, 'suppress_article_view_activity' ], 100 );

Expand Down Expand Up @@ -496,39 +497,120 @@ public static function is_post_restricted( $post_id = null ) {
*/
public static function create_gate( $title = '', $post_type = self::GATE_CPT ) {
$all_gates = self::get_gates();
return \wp_insert_post(
$gate_id = \wp_insert_post(
[
'post_title' => $title,
'post_type' => $post_type,
'post_status' => 'draft',
'post_content' => '<!-- wp:paragraph --><p>' . __( 'This post is only available to members.', 'newspack' ) . '</p><!-- /wp:paragraph -->',
'post_content' => self::get_default_gate_content(),
'meta_input' => [
'gate_priority' => count( $all_gates ),
],
]
],
true // Return WP_Error on failure.
);

if ( is_wp_error( $gate_id ) ) {
return $gate_id;
}

// Create default layouts for registration and custom_access modes.
$registration_content = self::get_block_pattern_content( 'registration-card' );
$registration_layout_id = self::create_gate_layout(
__( 'Registration Access Layout', 'newspack' ),
$registration_content
);
if ( ! is_wp_error( $registration_layout_id ) ) {
self::update_registration_settings( $gate_id, [ 'gate_layout_id' => $registration_layout_id ] );
}

$custom_access_layout_id = self::create_gate_layout(
__( 'Paid Access Layout', 'newspack' )
);
if ( ! is_wp_error( $custom_access_layout_id ) ) {
self::update_custom_access_settings( $gate_id, [ 'gate_layout_id' => $custom_access_layout_id ] );
}

Comment thread
miguelpeixe marked this conversation as resolved.
return $gate_id;
Comment thread
miguelpeixe marked this conversation as resolved.
}

/**
* Delete gate layouts when a gate is permanently deleted.
*
* @param int $post_id Post ID.
* @param \WP_Post $post Post object.
*/
public static function delete_gate_layouts( $post_id, $post ) {
if ( self::GATE_CPT !== $post->post_type ) {
return;
}

$gate = self::get_gate( $post_id );
if ( is_wp_error( $gate ) ) {
return;
}

// Delete registration layout if it exists.
if ( ! empty( $gate['registration']['gate_layout_id'] ) ) {
\wp_delete_post( $gate['registration']['gate_layout_id'], true );
}

// Delete custom access layout if it exists.
if ( ! empty( $gate['custom_access']['gate_layout_id'] ) ) {
\wp_delete_post( $gate['custom_access']['gate_layout_id'], true );
}
}
Comment thread
miguelpeixe marked this conversation as resolved.

/**
* Create a new gate layout post.
*
* @param string $title Optional gate layout title. Defaults to 'Content Gate Layout'.
* @param string $title Optional gate layout title. Defaults to 'Content Gate Layout'.
* @param string $content Optional post content. Defaults to a simple paragraph.
*
* @return int|\WP_Error The gate layout post ID or error if not created.
*/
public static function create_gate_layout( $title = '' ) {
public static function create_gate_layout( $title = '', $content = '' ) {
if ( empty( $title ) ) {
$title = __( 'Content Gate Layout', 'newspack' );
}
if ( empty( $content ) ) {
$content = self::get_default_gate_content();
}
return \wp_insert_post(
[
'post_title' => $title,
'post_type' => self::GATE_LAYOUT_CPT,
'post_content' => '<!-- wp:paragraph --><p>' . __( 'This post is only available to members.', 'newspack' ) . '</p><!-- /wp:paragraph -->',
]
'post_content' => $content,
],
true // Return WP_Error on failure.
);
}

/**
* Get block pattern content by slug.
*
* @param string $pattern_slug The pattern slug (e.g., 'registration-wall').
Comment thread
miguelpeixe marked this conversation as resolved.
*
* @return string The pattern content, or empty string if not found.
*/
public static function get_block_pattern_content( $pattern_slug ) {
$patterns_dir = realpath( __DIR__ . '/block-patterns' );
if ( ! $patterns_dir ) {
return '';
}

$path = realpath( $patterns_dir . '/' . $pattern_slug . '.php' );

// Ensure the resolved path is within the block-patterns directory to prevent directory traversal.
if ( ! $path || strpos( $path, $patterns_dir . DIRECTORY_SEPARATOR ) !== 0 ) {
return '';
}

ob_start();
require $path;
return ob_get_clean();
}

/**
* Get edit gate layout URL.
*
Expand Down Expand Up @@ -597,7 +679,9 @@ public static function handle_edit_gate_layout() {
\wp_safe_redirect( \get_edit_post_link( $gate_layout_id, 'edit' ) );
exit;
} else {
$gate_layout_id = self::create_gate_layout( $gate_layout_default_title );
// Use registration pattern for registration mode, default content for custom_access.
$gate_layout_content = 'registration' === $gate_mode ? self::get_block_pattern_content( 'registration-card' ) : '';
$gate_layout_id = self::create_gate_layout( $gate_layout_default_title, $gate_layout_content );
if ( is_wp_error( $gate_layout_id ) ) {
\wp_die( esc_html( $gate_layout_id->get_error_message() ) );
}
Expand Down
81 changes: 65 additions & 16 deletions includes/content-gate/trait-content-gate-layout.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,18 @@ protected static function get_layout_meta_config() {
];
}

/**
* Get the default value for a layout meta field.
*
* @param string $key The meta field key.
*
* @return mixed The default value, or null if not found.
*/
protected static function get_layout_meta_default( $key ) {
$config = self::get_layout_meta_config();
return $config[ $key ]['default'] ?? null;
}

/**
* Register layout meta fields for a given post type.
*
Expand Down Expand Up @@ -146,35 +158,59 @@ protected static function enqueue_block_editor_layout_assets( $post_type ) {
*/
protected static function get_visible_paragraphs( $gate_post_id ) {
$visible_paragraphs = \get_post_meta( $gate_post_id, 'visible_paragraphs', true );
return '' === $visible_paragraphs ? 2 : max( 0, (int) $visible_paragraphs );
return '' === $visible_paragraphs ? self::get_layout_meta_default( 'visible_paragraphs' ) : max( 0, (int) $visible_paragraphs );
}

/**
* Get the default gate content.
*
* @return string
*/
protected static function get_default_gate_content() {
return '<!-- wp:paragraph --><p>' . __( 'This post is only available to members.', 'newspack' ) . '</p><!-- /wp:paragraph -->';
}

/**
* Get the inline gate content with fade effect.
*
* @param int $gate_post_id The gate post ID.
* @param int $gate_layout_id The gate layout ID.
*
* @return string The inline gate HTML content.
*/
public static function get_inline_gate_content_for_post( $gate_post_id ) {
$style = \get_post_meta( $gate_post_id, 'style', true );
public static function get_inline_gate_content_for_post( $gate_layout_id ) {
$gate_layout_post = \get_post( $gate_layout_id );

// Get style, defaulting if post doesn't exist or meta is not set.
$style = $gate_layout_post ? \get_post_meta( $gate_layout_id, 'style', true ) : '';
if ( empty( $style ) ) {
$style = self::get_layout_meta_default( 'style' );
}

if ( 'inline' !== $style ) {
return '';
}
$gate = \get_the_content( null, false, \get_post( $gate_post_id ) );

// Add clearfix to the gate.
$gate = '<div style=\'content:"";clear:both;display:table;\'></div>' . $gate;
// Build gate content.
$gate_content = '<div style=\'content:"";clear:both;display:table;\'></div>';
if ( $gate_layout_post ) {
$gate_content .= \get_the_content( null, false, $gate_layout_post );
$visible_paragraphs = self::get_visible_paragraphs( $gate_layout_id );
$inline_fade = \get_post_meta( $gate_layout_id, 'inline_fade', true );
} else {
// Use defaults when layout post doesn't exist.
$gate_content .= self::get_default_gate_content();
$visible_paragraphs = self::get_layout_meta_default( 'visible_paragraphs' );
$inline_fade = self::get_layout_meta_default( 'inline_fade' );
}

// Apply inline fade.
$visible_paragraphs = self::get_visible_paragraphs( $gate_post_id );
if ( $visible_paragraphs > 0 && \get_post_meta( $gate_post_id, 'inline_fade', true ) ) {
$gate = '<div style="pointer-events: none; height: 10em; margin-top: -10em; width: 100%; position: absolute; background: linear-gradient(180deg, rgba(255,255,255,0) 14%, rgba(255,255,255,1) 76%);"></div>' . $gate;
if ( $visible_paragraphs > 0 && $inline_fade ) {
$gate_content = '<div style="pointer-events: none; height: 10em; margin-top: -10em; width: 100%; position: absolute; background: linear-gradient(180deg, rgba(255,255,255,0) 14%, rgba(255,255,255,1) 76%);"></div>' . $gate_content;
}

// Wrap gate in a div for styling.
$gate = '<div class="newspack-content-gate__gate newspack-content-gate__inline-gate">' . $gate . '</div>';
return $gate;
$gate_content = '<div class="newspack-content-gate__gate newspack-content-gate__inline-gate">' . $gate_content . '</div>';
return $gate_content;
}

/**
Expand All @@ -186,16 +222,29 @@ public static function get_inline_gate_content_for_post( $gate_post_id ) {
* @return string The restricted post excerpt HTML.
*/
public static function get_restricted_post_excerpt_for_gate( $post, $gate_layout_id ) {
$content = $post->post_content;
$content = $post->post_content;
$gate_layout_post = \get_post( $gate_layout_id );

$style = \get_post_meta( $gate_layout_id, 'style', true );
// Get settings from layout post, or use defaults if post doesn't exist.
if ( $gate_layout_post ) {
$style = \get_post_meta( $gate_layout_id, 'style', true );
$use_more_tag = \get_post_meta( $gate_layout_id, 'use_more_tag', true );
$count = self::get_visible_paragraphs( $gate_layout_id );
} else {
$style = '';
$use_more_tag = self::get_layout_meta_default( 'use_more_tag' );
$count = self::get_layout_meta_default( 'visible_paragraphs' );
}

// Default to configured style if not set.
if ( empty( $style ) ) {
$style = self::get_layout_meta_default( 'style' );
}

$use_more_tag = get_post_meta( $gate_layout_id, 'use_more_tag', true );
// Use <!--more--> as threshold if it exists.
if ( $use_more_tag && strpos( $content, '<!--more-->' ) ) {
$content = apply_filters( 'newspack_gate_content', explode( '<!--more-->', $content )[0] );
} else {
$count = self::get_visible_paragraphs( $gate_layout_id );
if ( 0 === $count ) {
return '';
}
Expand Down
Loading
Loading