Skip to content

feat: CPT content seeding (Tier-1 dynamic content)#5

Merged
BenKalsky merged 6 commits into
mainfrom
feat/cpt-seeding
Jun 2, 2026
Merged

feat: CPT content seeding (Tier-1 dynamic content)#5
BenKalsky merged 6 commits into
mainfrom
feat/cpt-seeding

Conversation

@BenKalsky
Copy link
Copy Markdown
Member

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, --execute to write; per-entry errors collected, batch continues. Dry-run/planning is stdlib-only (write-path deps imported lazily).
  • upload_media.py made importable.
  • Tests: unit (rest_base/terms resolution, dry-run planning) + offline dry-run smoke, wired into CI.
  • Bumped to 3.6.0.

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). --execute needs requests (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.
  • CI green.

🤖 Generated with Claude Code

BenKalsky and others added 6 commits June 2, 2026 19:22
…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>
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment on lines +66 to +69
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'])
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge 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)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge 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
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge 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 👍 / 👎.

@BenKalsky BenKalsky merged commit 3499a5f into main Jun 2, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant