feat: CPT content seeding (Tier-1 dynamic content)#5
Conversation
…helpers Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Write-path modules imported lazily so dry-run/planning needs only the stdlib. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a560c4c2e8
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if e.get('acf'): | ||
| _acf.set_acf_fields(url, user, pw, pid, e['acf']) | ||
| if e.get('jet'): | ||
| _jet.set_jetengine_fields(url, user, pw, pid, e['jet']) |
There was a problem hiding this comment.
Route field writes through the CPT endpoint
When an entry uses any post_type other than post and includes acf or jet, the CPT is created through its resolved REST base but these imported writers still POST to post-only routes (acf_fields.py uses /acf/v3/posts/{id} and /wp/v2/posts/{id}, and jetengine_fields.py uses /wp/v2/posts/{id}). WordPress does not expose CPT entries through /wp/v2/posts/{id}, and these helpers return error dictionaries that are ignored here, so seed_content.py reports the item as created while the dynamic fields were never populated.
Useful? React with 👍 / 👎.
| if e.get('featured_image') is not None: | ||
| mid = _resolve_image(url, user, pw, e['featured_image'], allow_remote) | ||
| if mid: | ||
| _media.set_featured_image(url, user, pw, pid, mid) |
There was a problem hiding this comment.
Set featured images using the CPT route
For CPT entries with featured_image, this calls upload_media.set_featured_image, which is hard-coded to POST /wp-json/wp/v2/posts/{post_id} and calls sys.exit(1) on failure. A CPT created via its own REST base will 404 on the posts endpoint, and because SystemExit is not caught by the surrounding except Exception, one featured image failure aborts the whole batch instead of collecting a per-entry error as documented.
Useful? React with 👍 / 👎.
| base_url = base_url.rstrip('/') | ||
| out = {} | ||
| for taxonomy, values in (terms_dict or {}).items(): | ||
| tax_base = resolve_rest_base(base_url, auth, taxonomy) # taxonomy rest_base |
There was a problem hiding this comment.
Resolve taxonomy REST bases from taxonomies
When a taxonomy has a custom rest_base, this uses the post-type resolver, which requests /wp/v2/types/{taxonomy} rather than the taxonomy descriptor endpoint. That request fails and falls back to the taxonomy slug, so term search/creation later targets /wp/v2/{taxonomy} and breaks for taxonomies whose REST collection is renamed (the same scenario this rest_base lookup is meant to handle).
Useful? React with 👍 / 👎.
What
Seed dynamic CPT datasets in one command — the content JetEngine/ACF listings render.
create_post.py:--post-type(resolves rest_base via/wp/v2/types) +--terms(name→id, create-missing). Now importable.describe_cpt.py(new): rest_base + taxonomies + field keys sampled from an existing entry.seed_content.py(new): JSON dataset → create entry + ACF + Jet + terms + featured image. Dry-run by default,--executeto write; per-entry errors collected, batch continues. Dry-run/planning is stdlib-only (write-path deps imported lazily).upload_media.pymade importable.Scope
Populates existing CPTs/taxonomies/field-groups; creating those is admin-side (out of scope). Flat ACF values (repeater/relational later). No upsert yet (re-run duplicates).
--executeneedsrequests(existing ACF/Jet dep).Test plan
python3 tests/test_cpt_seeding.py→ 4/4.seed_content.py --dataset tests/fixtures/seed.json→ dry-run plan, no network.🤖 Generated with Claude Code