Skip to content

cwp bricks pull

shipped 1.0.0
cwp bricks pull [env] [flags]

This name is an alias. The work moved to cwp pull --only bricks, and that page documents it. This spelling still runs for one minor cycle.

Acts on the local site. Name an environment to act there instead.

tree ← site

ArgumentWhat it isDefault
[env]environment to pull from (default: default_environment in cwp.yml)
FlagWhat it doesDefault
--type <type...>restrict to these transfer types (default: everything with content)
--sensitivedoes nothing since 2.0: credentials never enter the tree, and customCss travels on its ownoff
--no-assetsdo not fetch font files the export could not embed from an environmenton
--with-agentwith —dry-run on a host with no shell: install and remove the PHP agent so the plan is realoff

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

What it does

cwp bricks pull writes Bricks’ own transfer package into builder.options.export_dir as a tree of JSON. The default directory is bricks/. The tree holds manifest.json, styles/classes/classes.json and structure/templates/template-*.json.

You commit that tree. The ZIP Bricks produces is transient. The tree is what you read a diff on, and it makes an upward design change reproducible.

The builder’s settings travel by a rule per key. The run names every key it held back. This tree goes into git, so no flag opens a credential. What stays out, and why:

whatkeyswhy
per environmentmaintenanceModeowned by the access: map, applied by cwp access
credentialsthe API keys, the licence key, the template passwordsnever in a repository
code executionthe code toggles and the three script slotsnever over a push
post idslogin_page, maintenanceTemplate and seven moretravel as { kind: post, type, slug, uid } rather than a number that means another post on the other side
– settings — 2 key(s) held back from the tree — maintenanceMode (per environment, owned by access:), myTemplatesPassword (credential)

The pull does not hold a post id back. It translates the id, the way a settings: group with as: post-reference carries page_on_front, and cwp bricks push resolves it on the target. An id the site cannot describe stays a number.

Everything else in the six tabs is design and travels. That includes a key Bricks adds in a later release. The pull treats an unknown key as design unless it looks like a credential (apiKey*, apiSecretKey*, *Token, *Password). The api-keys and custom-code tabs never enter the tree. The one design key inside them, the custom CSS, travels as its own file (below). --sensitive has nothing left to switch on and says so when you pass it.

The scope is always explicit. The pull names every item by ID and writes ["all"] only for single-value types such as breakpoints.

The tree is the same from every environment

What Bricks exports describes the export as much as the design system. The package carries a timestamp, the exporting site’s URL and the post ID of every font and template. Its file name has today’s date on it. Pulled verbatim, that tree grows a new set of templates every day. It never matches the same design system pulled from another environment.

So cwp writes a committed form of the package instead:

  • cwp names font files by family: styles/custom-fonts/kulachat-hc.json, with its faces under assets/kulachat-hc/. cwp names each face after its weight and subset: 400.woff2, or 400-subset0.woff2 where a weight is split. Both names come out of the font’s own face map, which is the same on every environment. The path Bricks writes is not: it has carried the font’s post id, each file’s attachment id and whatever WordPress called the upload;
  • templates lose the export date: structure/templates/template-header.json;
  • the export timestamp, the site block, and every post and attachment ID come out;
  • cwp rewrites every JSON file with sorted keys and two-space indent, so a diff shows the element that changed rather than the file that did.

cwp reshapes nothing. Every field it removes is one Bricks’ importer never reads or falls back from. The importer matches fonts by family and templates by title and type. So the committed tree is still a package the importer accepts, and cwp bricks push sends it as it stands.

Pull twice and the second run reports 0 written, 18 unchanged. A pull that changes nothing leaves git status empty.

The first pull after upgrading writes the new names beside the old ones. A pull never deletes from a git-tracked directory. It reports the files it no longer produces and leaves them in place. git rm the dated templates and the id-suffixed font once, and the tree settles.

Custom fonts, and the files behind them

A Bricks custom font is a record and a binary in the media library. Bricks embeds the binary into the package by reading it off the local disk. On a workspace with pull.uploads: proxy the binary is not on disk. That is the uploads proxy working as designed. The export would drop every face, and the tree would record a font with no faces.

So the pull fetches the binary. When a font comes back empty, cwp asks Bricks which files that font needs, downloads those files from your environment into wp-content/uploads/, and exports again:

✓ font files — 1 fetched from dev into public/wp-content/uploads — 2026/02/example.woff

That is a handful of files, not the whole media library. The font then travels in the tree as styles/custom-fonts/assets/<family>/…. It is the one place where bricks/ is not JSON.

Nothing extra happens when nothing is missing. cwp reads the loss out of the package, not out of the site. The manifest counts the faces the database holds. The file counts the faces Bricks embedded. A gap between the two counts triggers the fetch.

--no-assets switches the fetch off. So does having nowhere to fetch from. If the project has several environments and none of them is dev, cwp says so rather than picking one. The pull reports the loss instead:

! Example Sans — 1 of 1 face(s) not embedded — styles/custom-fonts/example-sans-170.json

That tree is still usable for everything else. cwp bricks push refuses to send the font from it. The manual equivalent is:

cwp media pull dev --uploads sync
cwp pull --only bricks

Example

cwp bricks pull                                # everything with content, from local
cwp bricks pull --type classes --type variables
cwp bricks pull prod                           # read a remote instead

Templates leave once the content tree claims them

A Bricks template is a post. cwp content carries posts without rewriting their element ids. The design-system package cannot promise that, because Bricks’ importer regenerates every id when it upserts a template.

So the moment a content group declares bricks_template, the design system stops exporting the templates type. There is nothing to switch on: cwp reads it off content: in cwp.yml. The first pull after that reports the old files as left in place. git rm them and commit the move.

A project with no such group keeps exporting templates as before.

The options the builder’s own transfer leaves behind

Bricks stores two project-wide decisions in an option its export package does not carry: the colour mode (light, dark, or the visitor’s system preference) and the root font size behind every rem in the design system. settings: refuses both as belonging to the page builder.

cwp carries them in bricks/cwp-options.json. That is cwp’s own file in the builder’s tree: every pull writes it and every push reads it. You commit and diff it like everything else there. Bricks’ importer has no use for it. The push keeps it out of the archive on the way up.

Five more options the package omits travel in the same file:

  • the element manager (bricks_element_manager): which element is active, hidden or disabled;
  • the pseudo-classes the builder offers;
  • the locks on global classes;
  • the widget areas Bricks registers;
  • the global elements from before components.

A lock names a class by id. The package import can give a class a new id on the target. The push leaves out a lock on an id the target has no class for. The run names it.

The custom CSS is the second such file, bricks/custom.css. Bricks stores it under the custom-code tab beside the script slots, and its importer refuses that tab outright. The package can export the key and never import it. It is design all the same: on a real project it holds the light/dark switch for every image. The pull writes it as a CSS file. The push writes it back as one key. A diff shows lines of CSS rather than one JSON string. A site that has never saved custom CSS gets no file, and a tree with no file leaves the site’s CSS alone.

The run names two values under the same prefix that it does not carry. Absent never means overlooked:

– bricks_font_face_rules — not carried — generated by Bricks and regenerated on import
– bricks_mcp_settings — not carried — per environment

Hosts and attachments travel as placeholders

A class, a component or a template can name an image. The site names the image by its own host and its own attachment id. Neither means the same thing on another environment. The pull writes both as the content tree writes them: the host as {{site}}, the attachment as media:<upload path>. A tree pulled from dev and one pulled from prod are then the same bytes. The pull leaves the manifest and the font binaries alone.

An image on another host is not the site’s attachment. A reference a template library left behind, with an id and a URL under some other domain, travels as it is. The id means nothing on any site, and the URL is what renders.

What it does not do

It deletes nothing. Like cwp push without --delete, it is additive. The pull reports files in bricks/ that this export no longer contains and leaves them alone. Removing a git-tracked file is not a side effect of an export.

It writes nothing to the site it read from. Reading a remote is safe, so an environment argument here carries no guard ladder.