Skip to content

cwp content push

shipped 1.0.0
cwp content push [env] [flags]

Acts on the local site unless an environment is named.

ArgumentWhat it isDefault
[env]environment to write (omit for the local site)
FlagWhat it doesDefault
--post <selector...>slug, post id or URL — repeatable
--type <post_type>restrict to one post type
--allevery post in scopeoff
--forceoverride the protected-environment refusaloff
--no-backupskip the remote backup taken before the writeon
--yesskip the confirmation promptoff
--overwrite-conflictsoverwrite posts that changed on the target since cwp last saw themoff
--publishpublish a post that does not exist on the target yetoff
--status <status>set the status of every pushed post, new or existing
--media <mode>attachments the target lacks: upload them, or require them to be there alreadyupload

Plus the shared flags --json, --verbose and --dry-run.

What it does

Sends named posts from the committed tree to a site. Selection is explicit — --post, --type or --all — and every affected post is listed before anything happens.

What it refuses, and why each refusal is the point

A page changed on the target since cwp last saw it. Every transfer records _cwp_sync, the hash of the item as cwp left that site, so a push can tell “the tree moved” from “the site moved”. The second refuses with exit 5:

✗ 1 post(s) changed on "dev" since cwp last saw them
  → take their version with `cwp content pull dev --all`, or overwrite it with
    --overwrite-conflicts — the changed ones are listed above

--force does not override this, and that is deliberate. The two questions are unrelated: “yes, write to production” does not imply “yes, discard whatever an editor changed there”. Until 1.0 one flag answered both, so anyone forced to answer the first — which every push to a protected environment is — answered the second by accident.

A reference the target does not have. An element tree names element types and global class and component ids, none of which travel with the page, and all of which fail the same silent way: the page saves, the markup renders, and what you built is not what appears.

Each kind gets its own line because the fixes differ: an element type is code and travels with cwp deploy; a class or component is design-system state and travels with cwp bricks push.

! 3 components are not on "dev": 3c9e7c, b38830, c72701
  — send the design system first (`cwp bricks push dev`)

var(--x) is deliberately not checked. A CSS custom property is either a Bricks global variable or a plain declaration in the theme stylesheet, and the reference reads identically. On the first real page all five that an earlier version flagged were theme CSS, while every genuine Bricks variable was already on the target. A check that refuses correct pushes is worse than no check.

An attachment that is on neither side. --media upload, the default, sends files the target lacks and names every one in the confirmation; --media require refuses instead. Uploads go as base64 — Bricks’ upload ability rejects loopback URLs by design, so “let the remote fetch it from my DDEV site” has no working form. Files above 24 MB are refused with a measurement rather than a PHP memory error.

Defaults that are guards

  • A post that does not exist on the target is created as draft. --publish or --status says otherwise. An existing post’s status is not touched unless --status is given: pushing a layout fix must not publish a page somebody parked, and must not unpublish a live one.
  • Nothing is ever deleted on the target, and there is no --prune.
  • Meta cwp manages is replaced, not merged — a key the item no longer carries disappears — but only keys the group’s own include patterns claim. A plugin’s meta cwp never carried is none of its business.
  • The usual set: protected refuses without --force, a remote backup is taken first, the confirmation lists every affected post, and --dry-run runs every read-only preflight for real so the plan is truthful.

The rollback is per page

Bricks takes a revision before every element write, so each pushed page has an undo that costs nothing and undoes exactly that page — where the remote backup restores the whole app to fix one paragraph. The summary prints it:

push summary:
  about-us → dev (post 12783) — roll back:
    cwp ability bricks/restore-revision '{"revisionId":12791}' dev

Example

cwp content push dev --post about-us
cwp content push dev --all --dry-run
cwp content push prod --post about-us --force --publish

What it does not do

It deletes nothing on the target, pushes no media that exists on neither side, and merges nothing — a conflict is refused, not resolved.

It transfers no post type that no content group claims.