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
Original file line number Diff line number Diff line change
Expand Up @@ -36,16 +36,46 @@ function cdcf_get_source_post_id(int $post_id): int {
}

/**
* True if the source (EN) post has submitter meta from the public
* submission/referral form. Works whether called with the EN post ID
* or a translation's ID — resolves to source via cdcf_get_source_post_id().
* True if any post in this post's Polylang translation group carries
* submitter meta from the public submission/referral form.
*
* The submitter meta is written ONCE on the originally-submitted post
* — which is whatever language the human submitted in. A Spanish
* submission carries `_referral_submitter_email` on the ES post; the
* auto-translated EN/IT/FR/PT/DE siblings have no meta. So the helper
* walks the whole Polylang group and returns true if ANY sibling has
* the meta — not just the EN one — so the publish hook can recognize
* the submission regardless of which language sibling fired it.
*
* Production occurrence 2026-06-16: community_project 1534 was submitted
* in Spanish; the worker-promoted EN sibling 1556 failed the old
* EN-walk check and was never appended to /projects's
* community_projects field.
*
* Falls back to a single-post check when Polylang isn't active or the
* post is in no group.
*/
function cdcf_is_public_submission(int $post_id): bool {
$source_id = cdcf_get_source_post_id($post_id);
return (bool) (
get_post_meta($source_id, '_submission_submitter_email', true)
|| get_post_meta($source_id, '_referral_submitter_email', true)
);
$candidate_ids = [$post_id];
if (function_exists('pll_get_post_translations')) {
$group = pll_get_post_translations($post_id);
if (is_array($group) && !empty($group)) {
$candidate_ids = array_map('intval', array_values($group));
}
}

foreach ($candidate_ids as $id) {
if ($id <= 0) {
continue;
}
if (
get_post_meta($id, '_submission_submitter_email', true)
|| get_post_meta($id, '_referral_submitter_email', true)
) {
return true;
}
}
return false;
}

/**
Expand Down
54 changes: 38 additions & 16 deletions wordpress/themes/cdcf-headless/tests/SubmissionLifecycleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ public function test_get_source_post_id_falls_back_to_input_when_pll_returns_zer
public function test_is_public_submission_true_when_submission_email_present(): void
{
Functions\when('pll_get_post')->justReturn(0);
Functions\when('pll_get_post_translations')->justReturn([]);
Functions\when('get_post_meta')->alias(
static fn(int $id, string $key) => $key === '_submission_submitter_email'
? 'user@example.com'
Expand All @@ -130,6 +131,7 @@ public function test_is_public_submission_true_when_submission_email_present():
public function test_is_public_submission_true_when_referral_email_present(): void
{
Functions\when('pll_get_post')->justReturn(0);
Functions\when('pll_get_post_translations')->justReturn([]);
Functions\when('get_post_meta')->alias(
static fn(int $id, string $key) => $key === '_referral_submitter_email'
? 'referrer@example.com'
Expand All @@ -143,35 +145,55 @@ public function test_is_public_submission_true_when_referral_email_present(): vo
public function test_is_public_submission_false_when_no_submitter_meta(): void
{
Functions\when('pll_get_post')->justReturn(0);
Functions\when('pll_get_post_translations')->justReturn([]);
Functions\when('get_post_meta')->justReturn('');
$this->allowAllFunctionsToExist();

$this->assertFalse(cdcf_is_public_submission(42));
}

public function test_is_public_submission_resolves_translation_to_source_via_polylang(): void
public function test_is_public_submission_true_when_any_sibling_in_the_polylang_group_carries_submitter_meta(): void
{
// Called with translation ID 99; source is 42; meta on 42 says
// public submission. The function should return true.
// Walk the full Polylang group rather than the (EN-hardcoded) source
// returned by cdcf_get_source_post_id(). A Spanish public submission
// carries the submitter meta on the ES post itself; the auto-translated
// EN sibling has no meta. The submission still has to be treated as
// public when the hook fires for ANY sibling (including the EN one).
//
// Production occurrence 2026-06-16: community_project 1534 was submitted
// in Spanish with referral meta on 1534. After publish, the worker
// promoted EN sibling 1556 to publish, transition_post_status fired
// for 1556, the helper walked to 1556 (already the EN sibling) and
// saw no submitter meta — so cdcf_link_referral_on_publish bailed and
// 1556 was never appended to the EN /projects page's community_projects
// field.
$group = ['en' => 200, 'it' => 201, 'es' => 100, 'fr' => 202, 'pt' => 203, 'de' => 204];
Functions\when('pll_get_post')->alias(
static fn(int $id, string $lang) => $id === 99 && $lang === 'en' ? 42 : 0
static fn(int $id, string $lang) => $group[$lang] ?? 0
);
Functions\when('pll_get_post_translations')->alias(
static fn(int $id) => in_array($id, $group, true) ? $group : []
);
$metaCalls = [];
Functions\when('get_post_meta')->alias(
function (int $id, string $key) use (&$metaCalls): string {
$metaCalls[] = $id;
return $id === 42 && $key === '_submission_submitter_email'
? 'user@example.com'
: '';
}
static fn(int $id, string $key) =>
$id === 100 && $key === '_referral_submitter_email'
? 'submitter@example.com'
: ''
);
$this->allowAllFunctionsToExist();

$this->assertTrue(cdcf_is_public_submission(99));
// Meta reads should target the resolved source (42), not the
// translation (99).
$this->assertContains(42, $metaCalls);
$this->assertNotContains(99, $metaCalls);
$this->assertTrue(
cdcf_is_public_submission(200),
'Calling with the EN sibling (200) must still recognize the submission as public — the submitter meta lives on the ES original (100) in the same Polylang group.'
);
$this->assertTrue(
cdcf_is_public_submission(204),
'Calling with any other sibling (e.g. DE 204) must also recognize the submission as public.'
);
$this->assertTrue(
cdcf_is_public_submission(100),
'Calling with the source post itself (100) must recognize the submission as public — this is the simple legacy path.'
);
}

// ─── cdcf_enqueue_translations_for_submission ─────────────────────
Expand Down