From dace5e824c6e96fc2a7b5f86c70737f8fb296b5f Mon Sep 17 00:00:00 2001 From: Miguel Peixe Date: Mon, 18 May 2026 11:11:37 -0300 Subject: [PATCH 1/6] feat(reader-activation): add Content Gate fields to legacy sync --- .../reader-activation/sync/class-metadata.php | 1 + .../class-test-content-gate-legacy.php | 142 ++++++++++++++++++ 2 files changed, 143 insertions(+) create mode 100644 tests/unit-tests/reader-activation-sync/class-test-content-gate-legacy.php diff --git a/includes/reader-activation/sync/class-metadata.php b/includes/reader-activation/sync/class-metadata.php index edac4611b7..d1db7551b0 100644 --- a/includes/reader-activation/sync/class-metadata.php +++ b/includes/reader-activation/sync/class-metadata.php @@ -47,6 +47,7 @@ protected static function get_metadata_classes() { $classes = [ 'Legacy_Basic', 'Legacy_Payment', + 'Content_Gate', ]; } else { $classes = [ diff --git a/tests/unit-tests/reader-activation-sync/class-test-content-gate-legacy.php b/tests/unit-tests/reader-activation-sync/class-test-content-gate-legacy.php new file mode 100644 index 0000000000..56901eeb22 --- /dev/null +++ b/tests/unit-tests/reader-activation-sync/class-test-content-gate-legacy.php @@ -0,0 +1,142 @@ +factory->user->create( + [ + 'role' => 'subscriber', + 'user_email' => 'reader@example.com', + ] + ); + Reader_Activation::set_reader_verified( self::$user_id ); + } + + public function tear_down() { + Metadata::$version = self::$original_version; + Content_Gate_Metadata::reset_cache(); + parent::tear_down(); + } + + /** + * Create a published gate with active custom access rules. + * + * @param array $access_rules Access rules array. + * @return int Gate post ID. + */ + private function create_custom_access_gate( $access_rules ) { + $gate_id = $this->factory->post->create( + [ + 'post_type' => Content_Gate::GATE_CPT, + 'post_status' => 'publish', + 'post_title' => 'Legacy Gate', + ] + ); + update_post_meta( + $gate_id, + 'custom_access', + [ + 'active' => true, + 'access_rules' => $access_rules, + ] + ); + return $gate_id; + } + + /** + * Email-domain rule the seeded reader passes (reader@example.com). + * + * @return array + */ + private function passing_email_domain_rules() { + return [ + [ + [ + 'slug' => 'email_domain', + 'value' => 'example.com', + ], + ], + ]; + } + + public function test_legacy_schema_exposes_content_access_fields() { + $fields = Metadata::get_all_fields(); + $this->assertArrayHasKey( 'Content_Access', $fields, 'Legacy schema should expose the Content_Access field.' ); + $this->assertSame( 'Content Access', $fields['Content_Access'] ); + $this->assertArrayHasKey( 'Content_Access_Source', $fields ); + $this->assertArrayHasKey( 'Content_Access_Group', $fields ); + } + + public function test_legacy_schema_exposes_content_access_group_in_field_selector() { + $groups = Metadata::get_grouped_default_fields(); + $sections = array_column( $groups, 'section' ); + $this->assertContains( 'Content Access', $sections, 'The field selector should show a Content Access group on legacy sites.' ); + } + + public function test_legacy_normalize_keeps_content_access_when_enabled() { + $this->create_custom_access_gate( $this->passing_email_domain_rules() ); + Metadata::update_fields( [ 'Content Access' ] ); + + $contact = Metadata::get_contact_with_metadata( self::$user_id ); + $normalized = Metadata::normalize_contact_data( $contact ); + + $this->assertArrayHasKey( + 'NP_Content Access', + $normalized['metadata'], + 'Enabled Content Access field must survive legacy normalization.' + ); + $this->assertSame( 'Yes', $normalized['metadata']['NP_Content Access'] ); + } + + public function test_legacy_normalize_drops_content_access_when_not_enabled() { + $this->create_custom_access_gate( $this->passing_email_domain_rules() ); + Metadata::update_fields( [ 'Account' ] ); + + $contact = Metadata::get_contact_with_metadata( self::$user_id ); + $normalized = Metadata::normalize_contact_data( $contact ); + + $this->assertArrayNotHasKey( + 'NP_Content Access', + $normalized['metadata'], + 'Content Access must be dropped when not enabled for the integration.' + ); + } +} From e71dbc59978036def1a333d8d5d78633d1931ed4 Mon Sep 17 00:00:00 2001 From: Miguel Peixe Date: Mon, 18 May 2026 11:43:23 -0300 Subject: [PATCH 2/6] feat(reader-activation): gate Content Access fields on Content Gate feature --- .../sync/contact-metadata/class-content-gate.php | 2 +- .../class-test-content-gate-legacy.php | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/includes/reader-activation/sync/contact-metadata/class-content-gate.php b/includes/reader-activation/sync/contact-metadata/class-content-gate.php index 7a9ac58352..e21456e65a 100644 --- a/includes/reader-activation/sync/contact-metadata/class-content-gate.php +++ b/includes/reader-activation/sync/contact-metadata/class-content-gate.php @@ -41,7 +41,7 @@ public static function reset_cache() { * @return boolean */ public static function is_available() { - return true; + return Content_Gate_CPT::is_newspack_feature_enabled(); } /** diff --git a/tests/unit-tests/reader-activation-sync/class-test-content-gate-legacy.php b/tests/unit-tests/reader-activation-sync/class-test-content-gate-legacy.php index 56901eeb22..dbe2662cb7 100644 --- a/tests/unit-tests/reader-activation-sync/class-test-content-gate-legacy.php +++ b/tests/unit-tests/reader-activation-sync/class-test-content-gate-legacy.php @@ -34,6 +34,9 @@ class Test_Content_Gate_Legacy extends WP_UnitTestCase { public static function set_up_before_class() { parent::set_up_before_class(); require_once dirname( __DIR__, 2 ) . '/mocks/wc-mocks.php'; + if ( ! defined( 'NEWSPACK_CONTENT_GATES' ) ) { + define( 'NEWSPACK_CONTENT_GATES', true ); + } self::$original_version = Metadata::$version; } @@ -105,6 +108,18 @@ public function test_legacy_schema_exposes_content_access_fields() { $this->assertArrayHasKey( 'Content_Access_Group', $fields ); } + public function test_is_available_follows_content_gate_feature_flag() { + $this->assertTrue( + Content_Gate::is_newspack_feature_enabled(), + 'Sanity: the test enables the Content Gate feature.' + ); + $this->assertSame( + Content_Gate::is_newspack_feature_enabled(), + Content_Gate_Metadata::is_available(), + 'Content Gate metadata availability must delegate to the Content Gate feature flag.' + ); + } + public function test_legacy_schema_exposes_content_access_group_in_field_selector() { $groups = Metadata::get_grouped_default_fields(); $sections = array_column( $groups, 'section' ); From fc2297a369407347e8d158890629beac7cec4dd6 Mon Sep 17 00:00:00 2001 From: Miguel Peixe Date: Thu, 21 May 2026 10:53:29 -0300 Subject: [PATCH 3/6] fix(reader-activation): address Content Gate legacy sync review feedback --- .../integrations/class-integration.php | 6 +- .../class-test-prepare-contact.php | 30 ++++ .../class-test-content-gate-legacy.php | 140 +++++++++++++++++- 3 files changed, 168 insertions(+), 8 deletions(-) diff --git a/includes/reader-activation/integrations/class-integration.php b/includes/reader-activation/integrations/class-integration.php index c667727afa..9c0be7ceba 100644 --- a/includes/reader-activation/integrations/class-integration.php +++ b/includes/reader-activation/integrations/class-integration.php @@ -729,10 +729,12 @@ public function prepare_contact( $contact ) { $prepared = []; foreach ( $contact['metadata'] as $key => $value ) { - // If the key is already prefixed, keep it as-is if its field is enabled. + // If the key is already prefixed, keep it only when its field is both + // enabled and currently available — guarding against stale enabled-field + // names left over from a prior feature-flag-on period. if ( 0 === strpos( $key, $prefix ) ) { $field_name = substr( $key, strlen( $prefix ) ); - if ( in_array( $field_name, $enabled_fields, true ) ) { + if ( in_array( $field_name, $enabled_fields, true ) && in_array( $field_name, $keys_map, true ) ) { $prepared[ $key ] = $value; } continue; diff --git a/tests/unit-tests/integrations/class-test-prepare-contact.php b/tests/unit-tests/integrations/class-test-prepare-contact.php index 154fe6b73b..709943d2f9 100644 --- a/tests/unit-tests/integrations/class-test-prepare-contact.php +++ b/tests/unit-tests/integrations/class-test-prepare-contact.php @@ -282,6 +282,36 @@ public function test_preserves_email_and_name() { $this->assertSame( 'Test User', $result['name'] ); } + /** + * Test that an already-prefixed key whose field is enabled but no longer + * present in the live keys map (e.g. because a feature flag turned off the + * corresponding metadata class after the field was saved) is filtered out. + */ + public function test_already_prefixed_stale_enabled_field_filtered() { + $this->set_metadata_version( '1.0' ); + + // Write the enabled-fields option directly, bypassing the + // update_enabled_outgoing_fields() intersect filter, to simulate a stale + // saved field name that is no longer in the live keys map. + \update_option( 'newspack_integration_outgoing_fields_prepare-test', [ 'Stale Field' ] ); + + $keys_map = Metadata::get_keys(); + $this->assertNotContains( 'Stale Field', $keys_map, 'Sanity: stale field must not be in the live keys map.' ); + + $contact = [ + 'email' => 'test@example.com', + 'metadata' => [ 'NP_Stale Field' => 'leftover_value' ], + ]; + + $result = $this->integration->prepare_contact( $contact ); + + $this->assertArrayNotHasKey( + 'NP_Stale Field', + $result['metadata'], + 'Stale prefixed key must be dropped when its field is no longer available.' + ); + } + /** * Test mixed raw and already-prefixed keys in the same contact. */ diff --git a/tests/unit-tests/reader-activation-sync/class-test-content-gate-legacy.php b/tests/unit-tests/reader-activation-sync/class-test-content-gate-legacy.php index dbe2662cb7..cf945742e5 100644 --- a/tests/unit-tests/reader-activation-sync/class-test-content-gate-legacy.php +++ b/tests/unit-tests/reader-activation-sync/class-test-content-gate-legacy.php @@ -6,6 +6,7 @@ */ use Newspack\Content_Gate; +use Newspack\Institution; use Newspack\Reader_Activation; use Newspack\Reader_Activation\Sync\Metadata; use Newspack\Reader_Activation\Sync\Contact_Metadata\Content_Gate as Content_Gate_Metadata; @@ -24,6 +25,13 @@ class Test_Content_Gate_Legacy extends WP_UnitTestCase { */ private static $original_version; + /** + * Enabled outgoing fields restored in tear_down(). + * + * @var array|null + */ + private $original_enabled_fields; + /** * Verified reader user ID. * @@ -31,6 +39,15 @@ class Test_Content_Gate_Legacy extends WP_UnitTestCase { */ private static $user_id; + /** + * Define the Content Gates feature flag for this test class only. PHP + * defines cannot be unset, so once defined the flag stays on for the + * rest of the PHPUnit process — meaning any future test in the same + * process that asserts feature-off behavior would be silently + * neutralized. If such a test is added later, it must run in a + * separate process (e.g. @runInSeparateProcess). Defining in the + * bootstrap would have the same leak across the entire suite. + */ public static function set_up_before_class() { parent::set_up_before_class(); require_once dirname( __DIR__, 2 ) . '/mocks/wc-mocks.php'; @@ -43,8 +60,9 @@ public static function set_up_before_class() { public function set_up() { parent::set_up(); Content_Gate_Metadata::reset_cache(); - Metadata::$version = 'legacy'; - self::$user_id = $this->factory->user->create( + Metadata::$version = 'legacy'; + $this->original_enabled_fields = Metadata::get_fields(); + self::$user_id = $this->factory->user->create( [ 'role' => 'subscriber', 'user_email' => 'reader@example.com', @@ -54,6 +72,7 @@ public function set_up() { } public function tear_down() { + Metadata::update_fields( ! empty( $this->original_enabled_fields ) ? $this->original_enabled_fields : [] ); Metadata::$version = self::$original_version; Content_Gate_Metadata::reset_cache(); parent::tear_down(); @@ -62,15 +81,16 @@ public function tear_down() { /** * Create a published gate with active custom access rules. * - * @param array $access_rules Access rules array. + * @param array $access_rules Access rules array. + * @param string $title Optional gate title. * @return int Gate post ID. */ - private function create_custom_access_gate( $access_rules ) { + private function create_custom_access_gate( $access_rules, $title = 'Legacy Gate' ) { $gate_id = $this->factory->post->create( [ 'post_type' => Content_Gate::GATE_CPT, 'post_status' => 'publish', - 'post_title' => 'Legacy Gate', + 'post_title' => $title, ] ); update_post_meta( @@ -100,12 +120,27 @@ private function passing_email_domain_rules() { ]; } + /** + * Email-domain rule the seeded reader does not pass. + * + * @return array + */ + private function failing_email_domain_rules() { + return [ + [ + [ + 'slug' => 'email_domain', + 'value' => 'other.com', + ], + ], + ]; + } + public function test_legacy_schema_exposes_content_access_fields() { $fields = Metadata::get_all_fields(); $this->assertArrayHasKey( 'Content_Access', $fields, 'Legacy schema should expose the Content_Access field.' ); $this->assertSame( 'Content Access', $fields['Content_Access'] ); $this->assertArrayHasKey( 'Content_Access_Source', $fields ); - $this->assertArrayHasKey( 'Content_Access_Group', $fields ); } public function test_is_available_follows_content_gate_feature_flag() { @@ -154,4 +189,97 @@ public function test_legacy_normalize_drops_content_access_when_not_enabled() { 'Content Access must be dropped when not enabled for the integration.' ); } + + public function test_v1_schema_also_exposes_content_access_fields() { + Metadata::$version = '1.0'; + Content_Gate_Metadata::reset_cache(); + + $fields = Metadata::get_all_fields(); + $this->assertArrayHasKey( 'Content_Access', $fields, 'v1 schema should also expose Content_Access.' ); + $this->assertArrayHasKey( 'Content_Access_Source', $fields ); + } + + public function test_no_gate_matches_yields_content_access_no() { + $this->create_custom_access_gate( $this->failing_email_domain_rules() ); + Metadata::update_fields( [ 'Content Access' ] ); + + $contact = Metadata::get_contact_with_metadata( self::$user_id ); + $normalized = Metadata::normalize_contact_data( $contact ); + + $this->assertArrayHasKey( 'NP_Content Access', $normalized['metadata'] ); + $this->assertSame( + 'No', + $normalized['metadata']['NP_Content Access'], + 'When no custom-access gates grant access, Content_Access must be "No".' + ); + } + + public function test_legacy_normalize_keeps_already_prefixed_content_access_key() { + Metadata::update_fields( [ 'Content Access' ] ); + + $contact = [ + 'email' => 'reader@example.com', + 'metadata' => [ + 'NP_Content Access' => 'Yes', + ], + ]; + + $normalized = Metadata::normalize_contact_data( $contact ); + + $this->assertArrayHasKey( 'NP_Content Access', $normalized['metadata'] ); + $this->assertSame( 'Yes', $normalized['metadata']['NP_Content Access'] ); + } + + public function test_multiple_gates_aggregate_source_labels() { + $this->create_custom_access_gate( $this->passing_email_domain_rules(), 'Gate A' ); + $this->create_custom_access_gate( + [ + [ + [ + 'slug' => 'email_domain', + 'value' => 'example.com,otherdomain.com', + ], + ], + ], + 'Gate B' + ); + Metadata::update_fields( [ 'Content Access', 'Content Access Source' ] ); + + $contact = Metadata::get_contact_with_metadata( self::$user_id ); + $normalized = Metadata::normalize_contact_data( $contact ); + + $this->assertSame( 'Yes', $normalized['metadata']['NP_Content Access'] ); + $this->assertSame( + 'domain', + $normalized['metadata']['NP_Content Access Source'], + 'Duplicate domain labels from multiple gates must collapse to a single source value.' + ); + } + + public function test_institution_rule_path_yields_group_source() { + $institution_id = Institution::create( 'Test University', '', [ 'email_domain' => 'example.com' ] ); + $this->assertNotInstanceOf( WP_Error::class, $institution_id ); + + $this->create_custom_access_gate( + [ + [ + [ + 'slug' => 'institution', + 'value' => [ $institution_id ], + ], + ], + ] + ); + Metadata::update_fields( [ 'Content Access', 'Content Access Source' ] ); + + $contact = Metadata::get_contact_with_metadata( self::$user_id ); + $normalized = Metadata::normalize_contact_data( $contact ); + + $this->assertSame( 'Yes', $normalized['metadata']['NP_Content Access'] ); + $this->assertSame( + 'group', + $normalized['metadata']['NP_Content Access Source'], + 'Institution-rule passes must yield the "group" source label.' + ); + } } From 521ddfbb501bbe071175a5b88e7033fceb2f053a Mon Sep 17 00:00:00 2001 From: Miguel Peixe Date: Thu, 21 May 2026 11:18:24 -0300 Subject: [PATCH 4/6] fix(reader-activation): prefix Content_Gate metadata in legacy mode --- .../contact-metadata/class-content-gate.php | 34 +++++++++++++------ .../class-content-gate-metadata.php | 19 ++++++++++- .../class-test-content-gate-legacy.php | 17 ++++++++++ 3 files changed, 58 insertions(+), 12 deletions(-) diff --git a/includes/reader-activation/sync/contact-metadata/class-content-gate.php b/includes/reader-activation/sync/contact-metadata/class-content-gate.php index e21456e65a..b3bd31c2e5 100644 --- a/includes/reader-activation/sync/contact-metadata/class-content-gate.php +++ b/includes/reader-activation/sync/contact-metadata/class-content-gate.php @@ -8,6 +8,8 @@ namespace Newspack\Reader_Activation\Sync\Contact_Metadata; use Newspack\Reader_Activation\Sync\Contact_Metadata; +use Newspack\Reader_Activation\Sync\Legacy_Metadata; +use Newspack\Reader_Activation\Sync\Metadata; use Newspack\Access_Rules; use Newspack\Content_Gate as Content_Gate_CPT; use Newspack\Group_Subscription; @@ -78,26 +80,36 @@ public function get_metadata() { $custom_access_gates = self::get_custom_access_gates(); - // No custom access gates configured — nothing to evaluate. if ( empty( $custom_access_gates ) ) { - return [ + $metadata = [ 'Content_Access' => '', 'Content_Access_Source' => '', 'Content_Access_Group' => '', ]; + } else { + $evaluations = []; + foreach ( $custom_access_gates as $gate ) { + $evaluations[] = User_Gate_Access::evaluate_gate_for_user( $gate, $this->user->ID ); + } + + $user_id = $this->user->ID; + $metadata = [ + 'Content_Access' => self::has_content_access( $evaluations ) ? 'Yes' : 'No', + 'Content_Access_Source' => implode( ', ', self::collect_labels( $evaluations, $user_id, [ self::class, 'get_source_labels' ] ) ), + 'Content_Access_Group' => implode( ', ', self::collect_labels( $evaluations, $user_id, [ self::class, 'get_group_labels' ] ) ), + ]; } - $evaluations = []; - foreach ( $custom_access_gates as $gate ) { - $evaluations[] = User_Gate_Access::evaluate_gate_for_user( $gate, $this->user->ID ); + // In legacy mode the main sync path does not run a normalize step on + // the merged contact, so each metadata class must return keys in the + // prefixed shape (matching Legacy_Basic / Legacy_Payment). Without this, + // raw Content_Access keys are silently dropped at the ESP push. + if ( 'legacy' === Metadata::get_version() ) { + $normalized = Legacy_Metadata::normalize_contact_data( [ 'metadata' => $metadata ] ); + return $normalized['metadata'] ?? []; } - $user_id = $this->user->ID; - return [ - 'Content_Access' => self::has_content_access( $evaluations ) ? 'Yes' : 'No', - 'Content_Access_Source' => implode( ', ', self::collect_labels( $evaluations, $user_id, [ self::class, 'get_source_labels' ] ) ), - 'Content_Access_Group' => implode( ', ', self::collect_labels( $evaluations, $user_id, [ self::class, 'get_group_labels' ] ) ), - ]; + return $metadata; } /** diff --git a/tests/unit-tests/content-gate/class-content-gate-metadata.php b/tests/unit-tests/content-gate/class-content-gate-metadata.php index dc0efd535d..0f527f209d 100644 --- a/tests/unit-tests/content-gate/class-content-gate-metadata.php +++ b/tests/unit-tests/content-gate/class-content-gate-metadata.php @@ -10,6 +10,7 @@ use Newspack\Group_Subscription_Settings; use Newspack\Institution; use Newspack\Reader_Activation; +use Newspack\Reader_Activation\Sync\Metadata; use Newspack\Reader_Activation\Sync\Contact_Metadata\Content_Gate as Content_Gate_Metadata; /** @@ -41,6 +42,13 @@ class Newspack_Test_Content_Gate_Metadata extends WP_UnitTestCase { */ private $institution_ids = []; + /** + * Schema version restored in tear_down(). + * + * @var string + */ + private $original_version; + /** * Set up the WC mocks once for the class. */ @@ -51,6 +59,11 @@ public static function set_up_before_class() { /** * Set up before each test. + * + * Forces the v1 schema so get_metadata() returns the raw key shape these + * tests assert against — legacy mode now normalizes to prefixed keys + * (matching the other Legacy_* classes), which is exercised in + * Test_Content_Gate_Legacy. */ public function set_up() { parent::set_up(); @@ -63,7 +76,9 @@ public function set_up() { $subscriptions_database = []; $products_database = []; - self::$user_id = $this->factory->user->create( + $this->original_version = Metadata::$version; + Metadata::$version = '1.0'; + self::$user_id = $this->factory->user->create( [ 'role' => 'subscriber', 'user_email' => 'reader@example.com', @@ -93,6 +108,8 @@ public function tear_down() { Group_Subscription::reset_cache(); Institution::reset_matching_cache(); + Metadata::$version = $this->original_version; + Content_Gate_Metadata::reset_cache(); parent::tear_down(); } diff --git a/tests/unit-tests/reader-activation-sync/class-test-content-gate-legacy.php b/tests/unit-tests/reader-activation-sync/class-test-content-gate-legacy.php index cf945742e5..40a8e6572b 100644 --- a/tests/unit-tests/reader-activation-sync/class-test-content-gate-legacy.php +++ b/tests/unit-tests/reader-activation-sync/class-test-content-gate-legacy.php @@ -190,6 +190,23 @@ public function test_legacy_normalize_drops_content_access_when_not_enabled() { ); } + public function test_content_gate_fields_arrive_prefixed_from_get_contact_with_metadata() { + $this->create_custom_access_gate( $this->passing_email_domain_rules() ); + Metadata::update_fields( [ 'Content Access' ] ); + + // The main legacy sync path feeds get_contact_with_metadata() directly + // into the integration push without an additional normalize step — + // metadata classes must return prefixed keys to avoid silent drops. + $contact = Metadata::get_contact_with_metadata( self::$user_id ); + + $this->assertArrayHasKey( + 'NP_Content Access', + $contact['metadata'], + 'Content_Gate metadata must arrive prefixed from get_contact_with_metadata() in legacy mode.' + ); + $this->assertSame( 'Yes', $contact['metadata']['NP_Content Access'] ); + } + public function test_v1_schema_also_exposes_content_access_fields() { Metadata::$version = '1.0'; Content_Gate_Metadata::reset_cache(); From cf33f4b2f5932d4bf25938d64465eb00b4f1cfa9 Mon Sep 17 00:00:00 2001 From: Miguel Peixe Date: Thu, 21 May 2026 13:11:00 -0300 Subject: [PATCH 5/6] test(reader-activation): restore Content_Access_Group assertion and update institution label --- .../class-test-content-gate-legacy.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/unit-tests/reader-activation-sync/class-test-content-gate-legacy.php b/tests/unit-tests/reader-activation-sync/class-test-content-gate-legacy.php index 40a8e6572b..6c60b756cb 100644 --- a/tests/unit-tests/reader-activation-sync/class-test-content-gate-legacy.php +++ b/tests/unit-tests/reader-activation-sync/class-test-content-gate-legacy.php @@ -141,6 +141,7 @@ public function test_legacy_schema_exposes_content_access_fields() { $this->assertArrayHasKey( 'Content_Access', $fields, 'Legacy schema should expose the Content_Access field.' ); $this->assertSame( 'Content Access', $fields['Content_Access'] ); $this->assertArrayHasKey( 'Content_Access_Source', $fields ); + $this->assertArrayHasKey( 'Content_Access_Group', $fields ); } public function test_is_available_follows_content_gate_feature_flag() { @@ -273,7 +274,7 @@ public function test_multiple_gates_aggregate_source_labels() { ); } - public function test_institution_rule_path_yields_group_source() { + public function test_institution_rule_path_yields_institution_source() { $institution_id = Institution::create( 'Test University', '', [ 'email_domain' => 'example.com' ] ); $this->assertNotInstanceOf( WP_Error::class, $institution_id ); @@ -294,9 +295,9 @@ public function test_institution_rule_path_yields_group_source() { $this->assertSame( 'Yes', $normalized['metadata']['NP_Content Access'] ); $this->assertSame( - 'group', + 'institution', $normalized['metadata']['NP_Content Access Source'], - 'Institution-rule passes must yield the "group" source label.' + 'Institution-rule passes must yield the "institution" source label.' ); } } From 3f29a4fb73507afca95dbed7abd8cbd324b16472 Mon Sep 17 00:00:00 2001 From: Miguel Peixe Date: Thu, 21 May 2026 16:34:14 -0300 Subject: [PATCH 6/6] fix(reader-activation): correct text domain and stale docblock --- includes/reader-activation/sync/class-metadata.php | 2 +- .../sync/contact-metadata/class-content-gate.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/includes/reader-activation/sync/class-metadata.php b/includes/reader-activation/sync/class-metadata.php index d1db7551b0..3fbdfee613 100644 --- a/includes/reader-activation/sync/class-metadata.php +++ b/includes/reader-activation/sync/class-metadata.php @@ -38,7 +38,7 @@ class Metadata { /** * Get the metadata classes to be used for syncing contact metadata to the ESP. * - * These are the metadata classes that will be used in case get_version is not legacy. + * These are the metadata classes that will be used to build the full set of contact metadata fields. * * @return array List of metadata classes. */ diff --git a/includes/reader-activation/sync/contact-metadata/class-content-gate.php b/includes/reader-activation/sync/contact-metadata/class-content-gate.php index b3bd31c2e5..e50a3a2015 100644 --- a/includes/reader-activation/sync/contact-metadata/class-content-gate.php +++ b/includes/reader-activation/sync/contact-metadata/class-content-gate.php @@ -52,7 +52,7 @@ public static function is_available() { * @return string */ public static function get_section_name() { - return __( 'Content Access', 'newspack' ); + return __( 'Content Access', 'newspack-plugin' ); } /**