# WP ACF Use this skill for Websimple WordPress projects that use Advanced Custom Fields. Use `references/wp-theme-dev.md` for general PHP/theme structure, `references/wp-code-style.md` for PHPCS/PHPCBF, `references/wp-browser.md` for visual checks, and `references/wp-xdebug.md` for runtime debugging. ## Core principles - Keep ACF configuration predictable, portable, and version-controlled. - Prefer clear field names that map naturally to template usage. - Keep field registration/ACF hooks under `includes/vendors/acf.php` or the existing ACF vendor/module file. - Keep rendering logic in templates and reusable data helpers under `includes/` when needed. - Avoid changing field keys, field names, return formats, or option names casually; these may affect stored content. ## Local JSON ACF field group JSON definitions should live under the active theme's `acf-json/` directory. - Keep ACF JSON files version-controlled. - Preserve the project's existing JSON directory if one exists. - For greenfield projects, use `acf-json/` at the theme root. - Ensure the `acf-json/` directory exists and is writable by WordPress. - Do not delete or regenerate ACF JSON files without checking the diff. When local JSON is enabled, saving a field group, post type, taxonomy, or options page in wp-admin automatically creates or updates its JSON file. Do not tell the user to manually re-export JSON after normal dashboard saves; instead, remind them to review and commit the changed JSON file. There is no expected per-field-group `json_sync` flag in Websimple conventions. ACF local JSON is controlled by ACF's global JSON setting and save/load paths. ACF defaults local JSON on and uses the active theme's `acf-json/` folder unless customized. If PHP hooks customize ACF JSON paths, keep them in the ACF vendor/module file, e.g. `includes/vendors/acf.php`. ## Field group keys and filenames For greenfield field groups, use deterministic field group keys instead of ACF's auto-generated group keys. The field group key should match the JSON filename and describe what the group targets: ```text acf-json/group_post_project.json key: group_post_project ``` Examples: ```text group_post_project # fields for the project custom post type group_page_home # fields for the home page/template group_options_site # site options fields group_taxonomy_sector # fields for the sector taxonomy ``` ACF field keys inside the group may remain auto-generated. The deterministic-key convention applies primarily to field groups so JSON files stay organized and easy to find. For existing projects with auto-generated field group keys, preserve them unless the user explicitly approves a cleanup/migration. Do not rename existing field group keys casually because synced JSON, database references, and editor workflows may depend on them. ## Synchronizing ACF JSON For ACF 6.8+ with WP-CLI available, prefer the built-in ACF JSON CLI commands. Safe inspection: ```bash wp acf json status wp acf json sync --dry-run ``` Apply pending local JSON changes to the database: ```bash wp acf json sync ``` Useful scoped variants: ```bash wp acf json sync --type=field-group wp acf json sync --key=group_post_project ``` Notes: - `wp acf json sync` modifies the database; run `--dry-run` first, especially outside local development. - The command syncs pending local JSON changes for ACF item types such as field groups, post types, taxonomies, and options pages. - If no items are pending, expect an “already in sync” style result. - Do not use a guessed `--all` flag; current ACF CLI sync defaults to all supported item types unless scoped with `--type` or `--key`. If the project uses an older ACF/ACF PRO version without these commands: 1. Check the installed ACF version and whether an update is safe for the project. 2. If updating is low-risk and explicitly approved, update ACF/ACF PRO first, then use the CLI workflow. 3. Otherwise, use `references/wp-browser.md` to navigate wp-admin and sync from the ACF field group/admin screen. For production or staging, ask before updating plugins or syncing database-backed ACF changes. ## Field group organization Use field groups that reflect editorial concepts and template needs. Common grouping patterns: - page/template-specific fields; - reusable section/component fields; - site options; - post type-specific metadata; - taxonomy/user/menu-item metadata when needed. Avoid dumping unrelated fields into a single large group. Prefer labels and instructions that make sense to editors. ## Field naming Use stable, descriptive, snake_case field names. Good examples: ```text hero_title hero_text hero_image cta_link featured_posts background_color ``` Avoid vague names like `title_2`, `content_block`, or `misc` unless the existing project convention requires it. Do not rename existing field names unless the user accepts the content migration risk. ## Return formats Respect existing return formats. Changing them can break templates. Common preferences: - image fields: use the format already expected by the theme; arrays are useful when templates need alt/title/sizes; - link fields: arrays are usually practical for URL/title/target; - post object / relationship fields: know whether the field returns IDs or objects before using it; - true/false fields: handle empty/false explicitly. When uncertain, inspect the field group JSON or runtime value before changing template code. ## Template usage Prefer `get_field()` when the value needs escaping, conditionals, fallback handling, or reuse. ```php

``` Use compact output tags with escaping, following `references/wp-theme-dev.md`: ```php ``` Avoid `the_field()` for dynamic frontend output unless the value is known safe for the exact context. Prefer explicit escaping with `get_field()`. For image arrays: ```php <?= esc_attr( $image['alt'] ?? '' ); ?> ``` For link arrays: ```php ``` ## Options pages Keep ACF options-page registration in the ACF vendor/module file. Use options pages for true site-wide settings, not content that belongs to a page, post, taxonomy, or theme template. When reading option fields, make the option scope explicit: ```php ``` ## Flexible content and repeaters Keep flexible content layouts readable and component-oriented. - Use layout names that map to template partials or sections. - Keep layout fields scoped to what the layout renders. - Avoid deeply nested repeaters/flexible fields unless there is a strong editorial reason. - For complex flexible content rendering, prefer dispatching to template parts instead of one giant template file. The dispatch pattern depends on the theme. **Check whether the theme is a Kaliroots child theme first** (see `references/wp-kaliroots.md`) — Kaliroots has its own template lookup helpers and overriding them with generic WP dispatch fragments the resolution path. For a **generic (non-Kaliroots) WordPress theme**: ```php ``` For a **Kaliroots child theme**, dispatch through the Kaliroots section helper so child/parent override resolution works correctly: ```php ``` In a Kaliroots project, the section partial then lives at `templates/content/sections/{layout-name}.php` and is located via Kaliroots' lookup pipeline — see `references/wp-kaliroots.md` for the helper set and naming rules. Verify that the target partial exists before introducing either dispatch into an existing theme. If the project already uses a different established pattern, follow that — don't reorganize. Inside the layout partial, use `get_sub_field()` (not `get_field()`) to read layout sub-fields, and escape at output: ```php

``` ## Relationship and post object fields Before using relationship/post object fields, confirm whether they return IDs or post objects. - If using objects, restore global post state after setup. - If using IDs, use explicit IDs with WordPress APIs. - Avoid expensive relationship queries inside repeated templates when values can be prepared once. ## Refactoring workflow 1. Inspect the active theme, ACF plugin availability, existing ACF JSON path, and ACF-related include files. 2. Inspect existing field group JSON before changing field names, keys, return formats, or locations. 3. Keep PHP hooks/registration in the existing ACF module, usually `includes/vendors/acf.php`. 4. Keep template output escaped explicitly with `get_field()` where practical. 5. Make small, reversible changes. 6. After wp-admin field group edits, inspect the automatically updated `acf-json/` diff. 7. Run PHP lint/style checks via `references/wp-code-style.md` when PHP files changed. 8. Smoke-test affected frontend/admin behavior with `references/wp-browser.md` when relevant. 9. Inspect the diff, especially ACF JSON changes. ## Safety - Do not rename existing field names or change return formats without calling out content/template impact. - Do not delete ACF JSON files without explicit approval. - Do not expose secrets from options pages or database values. - Do not assume `the_field()` output is safe; escape based on context. - Preserve the project's existing ACF structure when it is coherent.