Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Account for password protected posts via protected_content feature #2408

Merged
merged 11 commits into from
Dec 3, 2021
89 changes: 86 additions & 3 deletions includes/classes/Feature/ProtectedContent/ProtectedContent.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
class ProtectedContent extends Feature {

/**
* Initialize feature setting it's config
* Initialize feature setting its config
*
* @since 3.0
*/
Expand All @@ -45,8 +45,16 @@ public function __construct() {
public function setup() {
add_filter( 'ep_indexable_post_status', [ $this, 'get_statuses' ] );
add_filter( 'ep_indexable_post_types', [ $this, 'post_types' ], 10, 1 );
add_filter( 'ep_admin_wp_query_integration', '__return_true' );
add_action( 'pre_get_posts', [ $this, 'integrate' ] );
add_filter( 'ep_post_formatted_args', [ $this, 'exclude_protected_posts' ], 10, 2 );
add_filter( 'ep_index_posts_args', [ $this, 'query_password_protected_posts' ] );
add_filter( 'ep_post_sync_args', [ $this, 'include_post_password' ], 10, 2 );
add_filter( 'ep_search_post_return_args', [ $this, 'return_post_password' ] );

if ( is_admin() ) {
add_filter( 'ep_admin_wp_query_integration', '__return_true' );
add_action( 'pre_get_posts', [ $this, 'integrate' ] );
add_filter( 'ep_post_query_db_args', [ $this, 'query_password_protected_posts' ] );
}

if ( Features::factory()->get_registered_feature( 'comments' )->is_active() ) {
add_filter( 'ep_indexable_comment_status', [ $this, 'get_comment_statuses' ] );
Expand Down Expand Up @@ -180,6 +188,81 @@ public function integrate( $query ) {
remove_filter( 'ep_formatted_args', [ $search_feature, 'weight_recent' ], 10 );
}

/**
* Query all posts with and without password for indexing.
*
* @since 4.0.0
*
* @param array $args Database arguments
* @return array
*/
public function query_password_protected_posts( $args ) {
$args['has_password'] = null;

return $args;
}

/**
* Include post password when indexing.
*
* @since 4.0.0
*
* @param array $post_args Post arguments
* @param int $post_id Post ID
* @return array
*/
public function include_post_password( $post_args, $post_id ) {
$post = get_post( $post_id );

// Assign null value so we can use the EXISTS filter.
$post_args['post_password'] = ! empty( $post->post_password ) ? $post->post_password : null;

return $post_args;
}

/**
* Exclude proctected post from the frontend queries.
*
* @since 4.0.0
*
* @param array $formatted_args Formatted Elasticsearch query
* @param array $args Query variables
* @return array
*/
public function exclude_protected_posts( $formatted_args, $args ) {
if ( empty( $args['has_password'] ) ) {
/**
* Filter to exclude protected posts from search.
*
* @hook ep_exclude_password_protected_from_search
* @param {bool} $exclude Exclude post from search.
* @return {bool}
*/
if ( ! is_user_logged_in() && apply_filters( 'ep_exclude_password_protected_from_search', true ) ) {
$formatted_args['post_filter']['bool']['must_not'][] = array(
'exists' => array(
'field' => 'post_password',
),
);
}
}

return $formatted_args;
}

/**
* Add post_password to post object properties set after query
*
* @since 4.0.0
*
* @param array $properties Post properties
* @return array
*/
public function return_post_password( $properties ) {
$properties[] = 'post_password';
return $properties;
}

/**
* Integrate EP into comment queries
*
Expand Down
1 change: 1 addition & 0 deletions includes/classes/Indexable/Post/Post.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ public function query_db( $args ) {
'order' => 'desc',
'no_found_rows' => false,
'ep_indexing_advanced_pagination' => true,
'has_password' => false,
];

if ( isset( $args['per_page'] ) ) {
Expand Down
3 changes: 3 additions & 0 deletions includes/mappings/post/5-2.php
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,9 @@
'post_excerpt' => array(
'type' => 'text',
),
'post_password' => array(
'type' => 'text',
),
'post_content' => array(
'type' => 'text',
),
Expand Down
3 changes: 3 additions & 0 deletions includes/mappings/post/7-0.php
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,9 @@
'post_excerpt' => array(
'type' => 'text',
),
'post_password' => array(
'type' => 'text',
),
'post_content' => array(
'type' => 'text',
),
Expand Down
151 changes: 151 additions & 0 deletions tests/php/features/TestProtectedContent.php
Original file line number Diff line number Diff line change
Expand Up @@ -229,4 +229,155 @@ public function testAdminCategories() {
$this->assertEquals( 2, $query->post_count );
$this->assertEquals( 2, $query->found_posts );
}

/**
* Check if passwords on posts are synced when feature not active
*
* @since 4.0.0
* @group protected-content
*/
public function testNoSyncPasswordedPost() {
add_filter( 'ep_post_sync_args', array( $this, 'filter_post_sync_args' ), 10, 1 );

$post_id = Functions\create_and_sync_post( array( 'post_password' => 'test' ) );

ElasticPress\Elasticsearch::factory()->refresh_indices();

// Check if ES post sync filter has been triggered
$this->assertNotEmpty( $this->applied_filters['ep_post_sync_args'] );

// Check if password was synced
$post = ElasticPress\Indexables::factory()->get( 'post' )->get( $post_id );

$this->assertArrayNotHasKey( 'post_password', $post );
}

/**
* Check if passwords on posts are synced when feature active
*
* @since 4.0.0
* @group protected-content
*/
public function testSyncPasswordedPost() {
ElasticPress\Features::factory()->activate_feature( 'protected_content' );
ElasticPress\Features::factory()->setup_features();

add_filter( 'ep_post_sync_args', array( $this, 'filter_post_sync_args' ), 10, 1 );

$post_id = Functions\create_and_sync_post( array( 'post_password' => 'test' ) );

ElasticPress\Elasticsearch::factory()->refresh_indices();

// Check if ES post sync filter has been triggered
$this->assertNotEmpty( $this->applied_filters['ep_post_sync_args'] );

// Check if password was synced
$post = ElasticPress\Indexables::factory()->get( 'post' )->get( $post_id );
$this->assertEquals( 'test', $post['post_password'] );

// Remove password from post
wp_update_post(
array(
'ID' => $post_id,
'post_password' => '',
) );

ElasticPress\Indexables::factory()->get( 'post' )->index( $post_id, true );
ElasticPress\Elasticsearch::factory()->refresh_indices();

$post = ElasticPress\Indexables::factory()->get( 'post' )->get( $post_id );

// Check if password was removed on sync
$this->assertEmpty( $post['post_password'] );

// Add back password on post
wp_update_post(
array(
'ID' => $post_id,
'post_password' => 'test',
) );

ElasticPress\Indexables::factory()->get( 'post' )->index( $post_id, true );
ElasticPress\Elasticsearch::factory()->refresh_indices();

$post = ElasticPress\Indexables::factory()->get( 'post' )->get( $post_id );

// Check if password was added back on sync
$this->assertEquals( 'test', $post['post_password'] );
}

/**
* Check if password protected post shows up in admin
*
* @since 4.0.0
* @group protected-content
*/
public function testAdminPasswordedPost() {
set_current_screen( 'edit.php' );

ElasticPress\Features::factory()->activate_feature( 'protected_content' );
ElasticPress\Features::factory()->setup_features();

Functions\create_and_sync_post(
array(
'post_content' => 'findme 123',
'post_password' => 'test'
)
);

ElasticPress\Elasticsearch::factory()->refresh_indices();

$query = new \WP_Query();

global $wp_the_query;

$wp_the_query = $query;

$args = array(
's' => 'findme',
);

$query->query( $args );

$this->assertTrue( $query->elasticsearch_success );
$this->assertEquals( 1, $query->post_count );
$this->assertEquals( 1, $query->found_posts );
}

/**
* Check password protected post in front-end
*
* @since 4.0.0
* @group protected-content
*/
public function testFrontEndSearchPasswordedPost() {
set_current_screen( 'front' );

ElasticPress\Features::factory()->activate_feature( 'protected_content' );
ElasticPress\Features::factory()->activate_feature( 'search' );
ElasticPress\Features::factory()->setup_features();

// Need to call this since it's hooked to init
ElasticPress\Features::factory()->get_registered_feature( 'search' )->search_setup();

Functions\create_and_sync_post(
array(
'post_content' => 'findme 123',
'post_password' => 'test',
)
);
ElasticPress\Elasticsearch::factory()->refresh_indices();

$query = new \WP_Query(
array(
's' => 'findme',
)
);

$this->assertTrue( $query->elasticsearch_success );

// Password post is expected to return as we are logged in.
$this->assertEquals( 1, $query->post_count );
$this->assertEquals( 1, $query->found_posts );
}
}