Skip to main content

ACF Test Strategy, Fixtures, and Scenario Matrix

ACF testing works when fixture data matches real editorial behavior, not just ideal input values.

Learning Focus

You will build deterministic fixture packs, map lifecycle scenarios across ACF hooks, and validate coverage with CLI commands that can run in local and CI environments.

Concept Overview

ACF bugs are frequently workflow bugs instead of syntax bugs. Fields look valid in isolation, but failures appear when drafts become publish candidates, when legacy meta formats coexist with new schemas, or when editors submit partial data. A good test strategy starts by reproducing those states deliberately.

Fixtures are your controlled content states. For ACF projects, a useful fixture set always includes at least one golden record, one partial record, and one legacy-format record. Golden records confirm expected behavior. Partial records confirm fallback and guard behavior. Legacy records confirm compatibility logic after schema changes.

A scenario matrix turns these fixtures into explicit coverage commitments. Each matrix row should include the input state, the hook stage, the expected validation behavior, and the expected post-save or render outcome. When each row maps to one automated test ID, you can detect coverage gaps before release. That traceability is what converts a test document into an engineering control.

The matrix also helps teams coordinate CI priorities. Not every scenario needs a full browser test. Many ACF behaviors can be validated with wp eval, wp eval-file, and small PHPUnit cases that apply hooks directly. This keeps test feedback fast while still catching high-impact data workflow issues.

Core Idea

Treat fixture design and scenario mapping as first-class code artifacts, then verify them with repeatable CLI checks before every release.

Mental Model

Think of it asBecause
Fixtures as controlled patients in a labYou need repeatable baseline conditions to trust outcomes
Scenario matrix as a flight checklistEvery critical stage must be confirmed before takeoff
Hook assertions as circuit breakersThey stop bad states before publication reaches users
CLI verification as pre-flight telemetryIt confirms runtime conditions without manual guesswork

Why It Matters

ApproachWhat HappensImpact in Production
Deterministic fixtures with golden, partial, and legacy recordsTests reproduce common and edge editorial statesFewer release surprises and faster incident triage
Matrix rows mapped to specific test IDsCoverage is measurable and auditableHigher confidence in CI pass signals
Hook-level validation tests for publish transitionsInvalid content states are blocked consistentlyBetter data quality and reduced support load
Fixture versioning alongside schema versionRefactors keep tests aligned with model changesLower regression risk during migrations
Ad hoc hand-made content for testing only (wrong pattern)Test state drifts between machines and runsFlaky pipelines and unreliable quality gates

Reference Table

Term/APISignature/SyntaxPurposeKey Notes
wp_insert_post()`wp_insert_post(array $postarr, bool $wp_error = false, bool $fire_after_hooks = true): intWP_Error`Create fixture posts for test packs
update_field()`update_field(string $selector, mixed $value, intstring $post_id = false): intbool`
get_field()`get_field(string $selector, intstring $post_id = false, bool $format_value = true): mixed`Read fixture values for assertions
acf/validate_valueadd_filter('acf/validate_value/name=field_name', callable $callback, int $priority = 10, int $accepted_args = 4): voidEnforce field and cross-field rulesCore validation hook for matrix pass/fail rows
acf/save_postadd_action('acf/save_post', callable $callback, int $priority = 10, int $accepted_args = 1): voidEnforce publish guard outcomesUse recursion guard when status is adjusted
have_rows()`have_rows(string $selector, intstring $post_id = false): bool`Iterate Repeater fixtures in tests
get_sub_field()get_sub_field(string $selector, bool $format_value = true, bool $escape_html = false): mixedValidate Repeater sub field content in assertionsACF Pro Required for Repeater field workflows
WP_UnitTestCase fixture lifecyclesetUp(): void and tearDown(): voidPrepare and clean fixture state for each test methodKeep tests isolated and deterministic
wp eval-filewp eval-file tests/fixtures/seed-script.phpExecute fixture seed scripts in CI/localFast validation without browser setup
ACF Pro Required

Rows using Repeater accessors (have_rows, get_sub_field) depend on ACF Pro field types.

Practical Use Cases

1. Seed deterministic service fixtures for local and CI environments

A healthcare service site has repeated regressions around optional disclaimers, date windows, and CTA fields. The team needs one command that always produces the same fixture records in every environment. Determinism here means stable slugs, stable values, and idempotent upsert behavior.

  1. Register a CLI command during acf/init so ACF APIs are guaranteed available.
  2. Upsert fixture pages by slug instead of creating random titles.
  3. Seed golden, partial, and legacy records with explicit values.
  4. Include a Repeater fixture set for FAQ content to test Pro field behavior.
  5. Persist a fixture manifest option with IDs and checksums for audit.
  6. Run command in local and CI before hook/unit tests.
wp-content/mu-plugins/clinic-acf-fixtures-service.php
<?php

declare(strict_types=1);

function clinic_acf_upsert_fixture_page(string $slug, string $title, string $status = 'draft'): int
{
$existing = get_page_by_path($slug, OBJECT, 'page');
if ($existing instanceof WP_Post) {
wp_update_post([
'ID' => (int) $existing->ID,
'post_title' => $title,
'post_status' => $status,
]);

return (int) $existing->ID;
}

return (int) wp_insert_post([
'post_type' => 'page',
'post_status' => $status,
'post_name' => $slug,
'post_title' => $title,
]);
}

add_action('acf/init', function (): void {
if (!defined('WP_CLI') || !WP_CLI || !class_exists('WP_CLI')) {
return;
}

WP_CLI::add_command('clinic-acf fixtures-seed-services', function (array $args, array $assocArgs): void {
$reset = isset($assocArgs['reset']) ? ((int) $assocArgs['reset'] === 1) : false;

$dataset = [
[
'slug' => 'fixture-service-golden',
'title' => 'Fixture Service Golden',
'status' => 'publish',
'fields' => [
'service_headline' => 'Personalized Acne Therapy Program',
'service_intro' => 'Structured treatment pathway with weekly skin response tracking.',
'service_cta_url' => 'https://example.com/book-consultation',
'service_phone' => '+65 6700 8899',
'service_start_date' => '2026-03-01',
'service_end_date' => '2026-06-30',
'service_has_disclaimer' => 1,
'service_disclaimer_text' => 'Consult a licensed physician before treatment.',
'service_faq_items' => [
['service_faq_question' => 'Is this suitable for sensitive skin?', 'service_faq_answer' => 'Yes, protocol is adjusted by skin response.'],
['service_faq_question' => 'How often are sessions scheduled?', 'service_faq_answer' => 'Most plans run every two weeks.'],
],
],
],
[
'slug' => 'fixture-service-partial',
'title' => 'Fixture Service Partial',
'status' => 'draft',
'fields' => [
'service_headline' => 'Partial Content for Validation',
'service_intro' => '',
'service_cta_url' => '',
'service_phone' => '',
'service_start_date' => '2026-05-01',
'service_end_date' => '2026-04-01',
'service_has_disclaimer' => 1,
'service_disclaimer_text' => '',
'service_faq_items' => [],
],
],
[
'slug' => 'fixture-service-legacy',
'title' => 'Fixture Service Legacy Format',
'status' => 'draft',
'fields' => [
'service_headline' => 'Legacy Import Heading',
'service_intro' => 'Imported from pre-2025 CMS export.',
'service_cta_url' => '/legacy-booking',
'service_phone' => '(65)67008899',
'service_start_date' => '2025-11-01',
'service_end_date' => '2026-01-15',
'service_has_disclaimer' => 0,
'service_disclaimer_text' => '',
'service_faq_items' => [
['service_faq_question' => 'Legacy FAQ', 'service_faq_answer' => 'Legacy answer format retained for compatibility tests.'],
],
],
],
];

$manifest = [];

foreach ($dataset as $record) {
$postId = clinic_acf_upsert_fixture_page($record['slug'], $record['title'], $record['status']);

if ($reset) {
delete_post_meta($postId, '_fixture_profile');
delete_post_meta($postId, '_fixture_checksum');
}

foreach ($record['fields'] as $fieldName => $fieldValue) {
update_field($fieldName, $fieldValue, $postId);
}

$checksum = hash('sha256', wp_json_encode($record['fields']));
update_post_meta($postId, '_fixture_profile', $record['slug']);
update_post_meta($postId, '_fixture_checksum', $checksum);

$manifest[] = [
'slug' => $record['slug'],
'post_id' => $postId,
'checksum' => $checksum,
];
}

update_option('clinic_acf_fixture_manifest_services', $manifest, false);
WP_CLI::log('seeded=' . count($manifest));
WP_CLI::log('manifest_hash=' . hash('sha256', wp_json_encode($manifest)));
WP_CLI::success('Service fixtures seeded.');
});
});
terminal: command
wp clinic-acf fixtures-seed-services --reset=1
wp option get clinic_acf_fixture_manifest_services --format=json
wp eval '$id=(int)get_page_by_path("fixture-service-golden", OBJECT, "page")->ID; var_export(get_field("service_headline", $id)); echo PHP_EOL;'
terminal: output
seeded=3
manifest_hash=31f3e8ff41c34c8be12f4f80d8de2bc95b5a7c8ec6502d64fa411d4d8f9f87d1
Success: Service fixtures seeded.
[{"slug":"fixture-service-golden","post_id":1204,"checksum":"d8f1f1a4de7f217ff833f2f4e7e482643f39dce40a5ea3733c3de15264274e6c"},{"slug":"fixture-service-partial","post_id":1205,"checksum":"9d45f91aacbc2c6a6d8fdf8fbdbdc6f8859e84d17c0f625d4f835fca28589a74"},{"slug":"fixture-service-legacy","post_id":1206,"checksum":"5d4e85117fd1212e7439b0158fe556153b2dc7817fc3c1b277e0f7165ca9e964"}]
'Personalized Acne Therapy Program'
warning

Never use randomly generated slugs or titles in baseline fixtures. Random fixtures break traceability between scenario matrix rows and automated tests.

2. Build and run a scenario matrix for validation and publish guard flows

The same service model has date rules and disclaimer requirements that must hold across draft and publish transitions. A scenario matrix should verify both acf/validate_value outcomes and final post status after acf/save_post. This use case turns matrix rows into executable checks.

  1. Add name-targeted validation for service_end_date relative to service_start_date.
  2. Add publish guard that demotes to draft when disclaimer is required but missing.
  3. Create a CLI command that runs matrix rows against real hook calls.
  4. Persist matrix results in an option for CI artifact capture.
  5. Fail pipeline if any row does not match expected result.
wp-content/mu-plugins/clinic-acf-scenario-matrix-service.php
<?php

declare(strict_types=1);

add_filter('acf/validate_value/name=service_end_date', function ($valid, $value, $field, $input) {
if ($valid !== true) {
return $valid;
}

$startRaw = '';
if (isset($_POST['acf']) && is_array($_POST['acf'])) {
$startRaw = (string) ($_POST['acf']['field_service_start_date'] ?? '');
}

$endRaw = (string) $value;
if ($startRaw === '' || $endRaw === '') {
return true;
}

$startTs = strtotime($startRaw);
$endTs = strtotime($endRaw);
if ($startTs === false || $endTs === false) {
return 'Start and end dates must be valid date values.';
}

if ($endTs < $startTs) {
return 'Service end date must be later than service start date.';
}

return true;
}, 10, 4);

add_action('acf/save_post', function ($post_id): void {
if (!is_numeric($post_id)) {
return;
}

static $guardLock = false;
if ($guardLock) {
return;
}

$postId = (int) $post_id;
$post = get_post($postId);
if (!$post instanceof WP_Post || $post->post_type !== 'page') {
return;
}

if ($post->post_status !== 'publish') {
return;
}

$requiresDisclaimer = (int) get_field('service_has_disclaimer', $postId) === 1;
$disclaimer = trim((string) get_field('service_disclaimer_text', $postId));

if (!$requiresDisclaimer || $disclaimer !== '') {
return;
}

$guardLock = true;
wp_update_post([
'ID' => $postId,
'post_status' => 'draft',
]);
update_post_meta($postId, '_service_publish_guard_reason', 'missing_disclaimer');
$guardLock = false;
}, 30);

add_action('acf/init', function (): void {
if (!defined('WP_CLI') || !WP_CLI || !class_exists('WP_CLI')) {
return;
}

WP_CLI::add_command('clinic-acf matrix-run-service-release', function (array $args, array $assocArgs): void {
$scenarios = [
[
'id' => 'SRV-001',
'slug' => 'fixture-matrix-valid-publish',
'start' => '2026-04-01',
'end' => '2026-04-30',
'has_disclaimer' => 1,
'disclaimer' => 'Doctor review required before treatment.',
'initial_status' => 'publish',
'expected_validation' => true,
'expected_status' => 'publish',
],
[
'id' => 'SRV-002',
'slug' => 'fixture-matrix-invalid-date',
'start' => '2026-05-20',
'end' => '2026-05-01',
'has_disclaimer' => 1,
'disclaimer' => 'Doctor review required before treatment.',
'initial_status' => 'publish',
'expected_validation' => 'Service end date must be later than service start date.',
'expected_status' => 'publish',
],
[
'id' => 'SRV-003',
'slug' => 'fixture-matrix-missing-disclaimer',
'start' => '2026-06-01',
'end' => '2026-06-20',
'has_disclaimer' => 1,
'disclaimer' => '',
'initial_status' => 'publish',
'expected_validation' => true,
'expected_status' => 'draft',
],
[
'id' => 'SRV-004',
'slug' => 'fixture-matrix-draft-allowed',
'start' => '2026-07-01',
'end' => '2026-07-15',
'has_disclaimer' => 1,
'disclaimer' => '',
'initial_status' => 'draft',
'expected_validation' => true,
'expected_status' => 'draft',
],
];

$results = [];
$passed = 0;

foreach ($scenarios as $scenario) {
$postId = clinic_acf_upsert_fixture_page($scenario['slug'], 'Fixture Matrix ' . $scenario['id'], $scenario['initial_status']);

update_field('service_start_date', $scenario['start'], $postId);
update_field('service_has_disclaimer', $scenario['has_disclaimer'], $postId);
update_field('service_disclaimer_text', $scenario['disclaimer'], $postId);

$_POST['acf'] = [
'field_service_start_date' => $scenario['start'],
];

$validation = apply_filters(
'acf/validate_value/name=service_end_date',
true,
$scenario['end'],
['name' => 'service_end_date'],
'acf[field_service_end_date]'
);

if ($validation === true) {
update_field('service_end_date', $scenario['end'], $postId);
}

wp_update_post([
'ID' => $postId,
'post_status' => $scenario['initial_status'],
]);

do_action('acf/save_post', $postId);

$status = (string) get_post($postId)->post_status;
$validationMatch = $validation === $scenario['expected_validation'];
$statusMatch = $status === $scenario['expected_status'];
$rowPassed = $validationMatch && $statusMatch;

if ($rowPassed) {
$passed++;
}

$results[] = [
'id' => $scenario['id'],
'post_id' => $postId,
'validation_result' => $validation,
'final_status' => $status,
'passed' => $rowPassed,
];
}

update_option('clinic_acf_matrix_report_service_release', $results, false);
WP_CLI::log('rows=' . count($results));
WP_CLI::log('passed=' . $passed);
WP_CLI::log('failed=' . (count($results) - $passed));
WP_CLI::success('Service release matrix complete.');
});
});
terminal: command
wp clinic-acf matrix-run-service-release
wp option get clinic_acf_matrix_report_service_release --format=json
wp eval '$rows=get_option("clinic_acf_matrix_report_service_release", []); $failed=array_filter($rows, static fn($r) => $r["passed"] !== true); echo "failed_rows=" . count($failed) . PHP_EOL;'
terminal: output
rows=4
passed=4
failed=0
Success: Service release matrix complete.
[{"id":"SRV-001","post_id":1301,"validation_result":true,"final_status":"publish","passed":true},{"id":"SRV-002","post_id":1302,"validation_result":"Service end date must be later than service start date.","final_status":"publish","passed":true},{"id":"SRV-003","post_id":1303,"validation_result":true,"final_status":"draft","passed":true},{"id":"SRV-004","post_id":1304,"validation_result":true,"final_status":"draft","passed":true}]
failed_rows=0
note

Keep matrix IDs stable across releases. Stable IDs let you trace regressions by scenario rather than by changing prose descriptions.

3. Edge case: random fixture generation creates flaky CI results

A team used random fixture titles and values so every run looked slightly different. As soon as tests started asserting sorted output or expected IDs, CI became flaky. The fix is deterministic fixture generation with stable slugs and a dataset hash.

Fragile Pattern (Bad)

wp-content/mu-plugins/clinic-acf-fixtures-random-fragile.php
<?php

declare(strict_types=1);

add_action('acf/init', function (): void {
if (!defined('WP_CLI') || !WP_CLI || !class_exists('WP_CLI')) {
return;
}

WP_CLI::add_command('clinic-acf fixtures-seed-random', function (): void {
$title = 'Fixture Random ' . wp_rand(1000, 9999);
$postId = (int) wp_insert_post([
'post_type' => 'page',
'post_status' => 'draft',
'post_title' => $title,
]);
update_field('service_phone', '+65 ' . wp_rand(1000, 9999) . ' ' . wp_rand(1000, 9999), $postId);
WP_CLI::success('Created random fixture ' . $postId . '.');
});
});

Robust Pattern (Good)

wp-content/mu-plugins/clinic-acf-fixtures-deterministic.php
<?php

declare(strict_types=1);

function clinic_acf_upsert_fixture_by_slug(string $slug, string $title): int
{
$existing = get_page_by_path($slug, OBJECT, 'page');
if ($existing instanceof WP_Post) {
wp_update_post([
'ID' => (int) $existing->ID,
'post_title' => $title,
'post_status' => 'draft',
]);

return (int) $existing->ID;
}

return (int) wp_insert_post([
'post_type' => 'page',
'post_status' => 'draft',
'post_name' => $slug,
'post_title' => $title,
]);
}

add_action('acf/init', function (): void {
if (!defined('WP_CLI') || !WP_CLI || !class_exists('WP_CLI')) {
return;
}

WP_CLI::add_command('clinic-acf fixtures-seed-deterministic', function (array $args, array $assocArgs): void {
$reset = isset($assocArgs['reset']) ? ((int) $assocArgs['reset'] === 1) : false;

$dataset = [
[
'slug' => 'fixture-deterministic-alpha',
'title' => 'Fixture Deterministic Alpha',
'fields' => [
'service_headline' => 'Deterministic Alpha Heading',
'service_phone' => '+65 6700 8899',
'service_start_date' => '2026-08-01',
'service_end_date' => '2026-08-21',
],
],
[
'slug' => 'fixture-deterministic-beta',
'title' => 'Fixture Deterministic Beta',
'fields' => [
'service_headline' => 'Deterministic Beta Heading',
'service_phone' => '+65 6700 8811',
'service_start_date' => '2026-09-01',
'service_end_date' => '2026-09-20',
],
],
];

$created = [];

foreach ($dataset as $record) {
$postId = clinic_acf_upsert_fixture_by_slug($record['slug'], $record['title']);

if ($reset) {
delete_post_meta($postId, '_fixture_deterministic_hash');
}

foreach ($record['fields'] as $fieldName => $fieldValue) {
update_field($fieldName, $fieldValue, $postId);
}

$hash = hash('sha256', wp_json_encode($record));
update_post_meta($postId, '_fixture_deterministic_hash', $hash);

$created[] = [
'slug' => $record['slug'],
'post_id' => $postId,
'hash' => $hash,
];
}

$datasetHash = hash('sha256', wp_json_encode($dataset));
update_option('clinic_acf_fixture_deterministic_manifest', $created, false);
WP_CLI::log('dataset_hash=' . $datasetHash);
WP_CLI::log('records=' . count($created));
WP_CLI::success('Deterministic fixtures seeded.');
});
});
terminal: command
wp clinic-acf fixtures-seed-random
wp clinic-acf fixtures-seed-random
wp clinic-acf fixtures-seed-deterministic --reset=1
wp clinic-acf fixtures-seed-deterministic --reset=1
terminal: output
Success: Created random fixture 1412.
Success: Created random fixture 1413.
dataset_hash=9cbe1a516788801efc1a2d27dbf4c1782a17573431f238f70971bbdb359f5fe1
records=2
Success: Deterministic fixtures seeded.
dataset_hash=9cbe1a516788801efc1a2d27dbf4c1782a17573431f238f70971bbdb359f5fe1
records=2
Success: Deterministic fixtures seeded.
warning

Flaky fixtures create false confidence in passing tests and false alarms in failing tests. Deterministic fixture hashes make this problem visible immediately.

Common Mistakes

MistakeRoot CauseWhat Breaks in ProductionCorrect Pattern
Only seeding happy-path recordsFixture planning ignores partial and legacy statesPublish-time validation failures appear after releaseRun wp clinic-acf fixtures-seed-services --reset=1 with golden, partial, and legacy profiles
Randomized fixture values in CITeam optimizes for speed over repeatabilityFlaky tests and unstable snapshotsUse stable slugs and verify with wp option get clinic_acf_fixture_deterministic_manifest --format=json
Matrix rows not linked to testsScenario docs are disconnected from codeCoverage gaps remain hiddenStore matrix output via update_option('clinic_acf_matrix_report_service_release', $results, false);
No publish guard assertion in matrixValidation-only testing strategyContent status regressions pass unnoticedRun wp clinic-acf matrix-run-service-release and assert final_status
Fixture scripts not idempotentScripts always create new postsData bloat and inconsistent test referencesUpsert by slug with get_page_by_path() and wp_update_post()
Legacy format not representedMigration compatibility ignoredOld records break in render and export pathsSeed one legacy profile and inspect with wp eval 'var_export(get_field("service_phone", (int)get_page_by_path("fixture-service-legacy", OBJECT, "page")->ID));'
Deep Dive: Why Random Fixture Bugs Are Harder to Debug Than They Look

Random fixtures make test failures appear non-reproducible because every rerun changes input values. Even when code is correct, output snapshots and sorted lists shift, so teams spend time chasing noise. This problem grows in CI where parallel jobs run with different random seeds. The fix is deterministic input plus a manifest hash that proves fixture identity across runs. Once the hash is stable, a test failure is much more likely to represent a real regression.

wp eval '$manifest=get_option("clinic_acf_fixture_deterministic_manifest", []); echo hash("sha256", wp_json_encode($manifest)) . PHP_EOL;'

Best Practices

  1. Keep fixture slugs stable and verify lookup with wp eval '$id=(int)get_page_by_path("fixture-service-golden", OBJECT, "page")->ID; echo $id . PHP_EOL;'.
  2. Add one legacy-format profile per content model and confirm with wp eval '$id=(int)get_page_by_path("fixture-service-legacy", OBJECT, "page")->ID; var_export(get_field("service_cta_url", $id)); echo PHP_EOL;'.
  3. Use idempotent upsert functions (get_page_by_path, wp_update_post) instead of always creating new posts.
  4. Track fixture manifest checksums and assert with wp option get clinic_acf_fixture_manifest_services --format=json.
  5. Execute matrix checks in CI with wp clinic-acf matrix-run-service-release and fail pipeline on non-zero failed rows.
  6. Include publish and draft transition rows in every matrix, not only validation rows.
  7. Store matrix report artifacts using update_option('clinic_acf_matrix_report_service_release', $results, false); so failures can be audited.

Hands-On Practice

Exercise 1: Seed baseline service fixtures

Run:

wp clinic-acf fixtures-seed-services --reset=1
wp post list --post_type=page --search="Fixture Service" --fields=ID,post_name,post_status --format=table

After completing this exercise, output should include these slugs:

fixture-service-golden
fixture-service-partial
fixture-service-legacy

Exercise 2: Verify deterministic manifest and checksums

Run:

wp option get clinic_acf_fixture_manifest_services --format=json

After completing this exercise, output should show three objects with keys:

slug
post_id
checksum

Exercise 3: Execute scenario matrix command

Run:

wp clinic-acf matrix-run-service-release

After completing this exercise, output should include:

rows=4
passed=4
failed=0

Exercise 4: Inspect one failing-mode matrix row manually

Run:

wp eval '$rows=get_option("clinic_acf_matrix_report_service_release", []); foreach ($rows as $row) { if ($row["id"] === "SRV-003") { print_r($row); } }'

After completing this exercise, output should include:

[id] => SRV-003
[final_status] => draft
[passed] => 1

Exercise 5: Compare random and deterministic fixture behavior

Run:

wp clinic-acf fixtures-seed-random
wp clinic-acf fixtures-seed-random
wp clinic-acf fixtures-seed-deterministic --reset=1
wp clinic-acf fixtures-seed-deterministic --reset=1

After completing this exercise, output should show different random post IDs but identical deterministic dataset_hash values on repeated deterministic runs.

CLI Reference

CommandPurposeReal Example Output
wp clinic-acf fixtures-seed-services --reset=1Seed deterministic golden, partial, and legacy fixture profilesseeded=3 and Success: Service fixtures seeded.
wp option get clinic_acf_fixture_manifest_services --format=jsonInspect fixture manifest IDs and checksums[{"slug":"fixture-service-golden","post_id":1204,"checksum":"d8f1f1a4de7f217ff833f2f4e7e482643f39dce40a5ea3733c3de15264274e6c"}]
wp clinic-acf matrix-run-service-releaseExecute matrix assertions for validation and publish guardrows=4 passed=4 failed=0
wp option get clinic_acf_matrix_report_service_release --format=jsonRead full scenario matrix result payload[{"id":"SRV-001","post_id":1301,"validation_result":true,"final_status":"publish","passed":true}]
wp eval '$rows=get_option("clinic_acf_matrix_report_service_release", []); $failed=array_filter($rows, static fn($r) => $r["passed"] !== true); echo count($failed) . PHP_EOL;'Count failed matrix rows for CI gate0
wp eval '$id=(int)get_page_by_path("fixture-service-golden", OBJECT, "page")->ID; var_export(get_field("service_headline", $id)); echo PHP_EOL;'Confirm golden fixture field value'Personalized Acne Therapy Program'
wp clinic-acf fixtures-seed-randomDemonstrate fragile non-deterministic fixture commandSuccess: Created random fixture 1412.
wp clinic-acf fixtures-seed-deterministic --reset=1Seed deterministic fixture set with stable hashdataset_hash=9cbe1a516788801efc1a2d27dbf4c1782a17573431f238f70971bbdb359f5fe1
wp eval '$manifest=get_option("clinic_acf_fixture_deterministic_manifest", []); echo hash("sha256", wp_json_encode($manifest)) . PHP_EOL;'Validate deterministic manifest identityc91d3cbfd9a8bd708f4054f06052208e0fc4aa4dfb9722d82b0d2e7f0e7aa278

What's Next

tip

Revisit this lesson whenever you add or rename critical fields, because fixture drift is usually the first cause of false confidence in a passing test suite.