WP Manifestindependent plugin directory
manifest / updates / code-builder

Code Builder self-updates

A wordpress plugin that used to serve, deploy hardcoded codes from github and share domain and server with the existing wordpress site.

by jeydweirdough · github.com/jeydweirdough/code-builder

0stars
0forks

Install

The author publishes release zips, so WP-CLI can install straight from GitHub:

wp plugin install https://github.com/jeydweirdough/code-builder/releases/download/v1.1.0/code-builder-1.1.0.zip

Ships its own WordPress updater (built-in updater), so new versions show up under Dashboard → Updates.

Readme

Code Builder

Deploys Git repositories on your own WordPress server. It clones the repo to disk, runs its install and build commands, and serves the build output as real files at /app/{project}/ — with per-project access control, live build logs, and one-click rollback across the last 5 builds.

Because the output is real files on disk, everything that normally breaks when a site is reassembled from a database works here: relative paths, @font-face URLs, video files, source maps, and bundler-hashed filenames like index-BaR9xQ7z.js.

A project can also take over the site root instead of living at /app/, be built in CI and posted here when the server can't build it, and keep its rollback history in cloud storage when disk is tight. Projects → System Health tells you what your server actually supports.


Filling in the Build settings

This is the part most people get stuck on, so start here.

You usually don't have to fill anything in. Leave Install Command, Build Command and Output Directory blank and hit Deploy. Code Builder reads your repository — its package.json, lockfile and config files — works out the right values, uses them, and then writes them back into the form so you can see exactly what it decided and adjust from there.

Fill a field in yourself only when you want to override that decision. A value you type always wins; a blank field means "figure it out".

The three fields

Field What it is Blank means
Install Command Fetches dependencies. Runs first. Detected from your lockfile
Build Command Compiles the site. Runs second. Detected from your package.json scripts
Output Directory The folder that gets published Auto-probed after the build

All three are optional. A repository of hand-written HTML needs none of them.

What gets detected, by project type

Find your project in the left column. The three right-hand columns are what Code Builder fills in — and what you should enter if you'd rather set it manually.

Your repository has… Install Command Build Command Output Directory
vite.config.js / .ts npm install npm run build dist
Vite + React npm install npm run build dist
Vite + Vue npm install npm run build dist
next.config.js or a next dependency npm install npm run build out
angular.json npm install npm run build dist (see note)
nuxt.config.ts or a nuxt dependency npm install npm run build dist
react-scripts (Create React App) npm install npm run build build
React without a bundler config npm install npm run build build
tailwind.config.js, or @tailwindcss/cli npm install npm run build:css (blank — repo root)
composer.json only composer install --no-dev --optimize-autoloader (none) (blank — repo root)
index.php / header.php, no JS build (none) (none) (blank — repo root)
Plain .html / .css / .js files (none) (none) (blank — repo root)

npm install is shortened for readability in that table — the real detected value carries flags (npm install --no-audit --no-fund), and a pnpm/yarn/bun project gets its own tool instead. The next section gives the exact strings.

Angular and Nuxt nest one level deeper than everyone else — dist/my-app/browser. You don't need to write that out. When the folder you point at contains exactly one folder and nothing else, Code Builder walks down into it automatically, up to three levels.

Which package manager gets used

Your lockfile decides, not your preference. Running npm install in a repo with a pnpm-lock.yaml produces a different dependency tree than the one the project's authors tested, and that difference is a real source of "works locally, breaks on the server".

Lockfile in the repo Install Command used
pnpm-lock.yaml pnpm install --frozen-lockfile
bun.lockb or bun.lock bun install
yarn.lock yarn install --frozen-lockfile
package-lock.json npm install --no-audit --no-fund
package.json, no lockfile npm install --no-audit --no-fund
composer.json, no package.json composer install --no-dev --optimize-autoloader

The build command uses the same tool: a pnpm project gets pnpm run build, not npm run build.

Why npm install and not npm ci? npm ci is stricter and technically more correct, but it hard-fails when package-lock.json and package.json have drifted apart — which happens constantly in repos where package.json gets edited by hand. A deploy shouldn't need babysitting, so the more forgiving command is the default. Type npm ci into the field yourself if you want the strict behaviour.

Which npm script gets picked

Code Builder looks through your package.json scripts block in this order and takes the first one that exists:

build  →  build:prod  →  build:production  →  build:css  →  export  →  generate

If none of those exist, no build command runs — which is correct for a repository that has nothing to compile.

That build:css entry is there for a specific and common case: a hand-written HTML or PHP site whose only build step compiles a Tailwind stylesheet in place. Such a repo typically has no build script at all, just:

{
  "scripts": {
    "build:css": "tailwindcss -i ./assets/input.css -o ./assets/tailwind.css --minify"
  }
}

Nothing is bundled, so the output directory is the repository root — the site is the source tree, with one stylesheet freshly compiled inside it. Leave Output Directory blank for these.

How Output Directory is auto-probed

When you leave it blank, Code Builder looks for the first of these that exists and isn't empty, then descends into any single-folder nesting:

dist  →  build  →  out  →  _site  →  public

If none of them exist, it publishes the repository root. That is the right answer for static sites, PHP sites and Tailwind-only sites, and the wrong answer for a bundled app whose build failed to produce anything — which is why an empty result stops the deploy with an error rather than publishing a source tree.


Rules for the command fields

One command per field. No shell operators.

This is rejected:

npm install && npm run build          ✗  no  &&
npm run build; echo done              ✗  no  ;
npm run build | tee build.log         ✗  no  pipes
npm run build > output.txt            ✗  no  redirects
npm run $(cat which-script.txt)       ✗  no  command substitution

Chain steps inside a package.json script instead, and call that:

{
  "scripts": {
    "deploy": "npm run clean && npm run build:css && vite build"
  }
}

…then set Build Command to npm run deploy. This is better anyway: the steps live in your repo where they're version-controlled and reviewable, and the build log attributes failures to the step that actually failed.

The executable must be one of these:

npm   npx   pnpm   pnpx   yarn   bun   bunx   node
composer   php   git   make   hugo   tailwindcss   sass   vite

A command that breaks either rule isn't saved, and the form tells you so rather than accepting it and silently skipping the step at deploy time.

Flags and arguments are fine — composer install --no-dev, npx tailwindcss -i ./src/input.css -o ./dist/out.css --minify. Quoted arguments with spaces in them are preserved.


The other project settings

Root Directory

For a monorepo: the subfolder the build runs in. If your site lives in packages/web/, put that here, and Install/Build/Output are all resolved relative to it. Blank means the repository root.

Framework

Cosmetic — it sets the badge shown on the project card. What actually determines the build is the three command fields above. It's filled in automatically on first deploy.

Who can view it

Checked on every request, including images, fonts and scripts.

Setting Who gets through
Public Everyone
Logged-in users Any logged-in WordPress user (others are sent to the login form)
Administrators only Users with manage_options

This is meaningful rather than decorative: build files are made unreadable directly on disk (a deny rule is written into wp-content/code-builder/), so /app/{project}/ is the only route to them.

SPA fallback

Turn this on for a client-routed app — React Router, Vue Router, TanStack Router. Without it, loading /app/mysite/dashboard directly returns 404, because there is no dashboard file on disk; with it, index.html is served and your router takes over.

Requests that look like an asset (anything with an extension other than .html) still 404 properly. Handing index.html to a missing .js request would turn a clean 404 into a JavaScript syntax error, which is much harder to debug.

Leave it off for static sites and multi-page sites — it would mask genuine broken links.

You may not need it at all: an extensionless URL is already matched against a matching .html file, so /app/mysite/about finds about.html on its own. That covers most static site generators without any fallback.

Auto-deploy

Deploys on every push to the tracked branch. Two mechanisms, and you get whichever works on your host:

  • Deploy hook — copy the Payload URL and Secret from the project's Settings tab into your repository's Settings → Webhooks (content type: JSON). Instant.
  • Hourly check — if GitHub can't reach your site (local, staging behind a VPN, IP-allowlisted), a scheduled check compares the branch's latest commit against the last one deployed and deploys only when it has changed.

Serving a project at the site root

By default a project lives at /app/{project}/. If you want it to be the site — at example.com/ rather than example.com/app/mysite/ — go to GitHub Defaults → Override Controls, pick the project, and tick what it should take over.

There are two switches because they're useful separately.

Override Main Site (/)

The project becomes your site's front end. It answers / and every page URL beneath it, and a URL the build has no file for returns the project's 404.

This means your WordPress pages, posts and archives stop being reachable at their URLs. That is the intended behaviour, not a side effect: two different answers for one URL is exactly what makes a migrated site feel broken. Nothing is deleted — unticking the box brings everything back immediately.

What is never taken over, so you can always get back in and turn it off:

/wp-admin/        /wp-login.php     /wp-json/      admin-ajax.php
wp-cron.php       xmlrpc.php        /feed/         wp-sitemap.xml
robots.txt        ?rest_route=…     ?preview=…     /app/{project}/

That last one matters: the project stays addressable at its own /app/ URL even while it's serving the root, so you can always compare the two.

If the project has never been deployed, nothing is taken over. With no build on disk the override stands aside entirely and your site carries on as it was. The same applies if a build's files are later deleted — it fails open rather than blanking the site.

Override Assets (/assets/)

Serves static files — images, CSS, JS, fonts — from the build at root-level paths. Useful on its own when you want project pages to stay at /app/{project}/ but their assets to resolve from /assets/….

One thing to know: "asset" is decided by file extension, and .xml counts as one. If a plugin such as Yoast serves /sitemap.xml, it will 404 while this is ticked. WordPress's own wp-sitemap.xml is unaffected.


Deploying a build made somewhere else

Some repositories can't be built on the WordPress host at all — proc_open is disabled, or the build needs more memory or a newer Node than the server has. For those, build in CI and post the finished output here.

Endpoint — shown on the project's Settings tab:

POST /wp-json/code-builder/v1/deploy-artifact/{project-slug}

From GitHub Actions, or any CI:

cd dist && zip -qr ../build.zip . && cd ..
gzip -kc build.log > build.log.gz

curl -f -X POST "https://example.com/wp-json/code-builder/v1/deploy-artifact/mysite" \
  -H "X-CPB-Token: $CODE_BUILDER_SECRET" \
  -F "artifact=@build.zip" \
  -F "log=@build.log.gz" \
  -F "sha=$GITHUB_SHA"

$CODE_BUILDER_SECRET is the same webhook secret from the Settings tab. Only artifact is required.

Everything after extraction is the normal pipeline, so an artifact deploy gets the same release directory, the same rollback, the same pruning and the same access control as a git deploy. It needs no git, no Node and no proc_open — only PHP's zip extension.

The build log

Send your CI log as log and it's stored with the deployment and shown in the Logs tab, so the record of how a build was produced lives next to the build.

Gzipped or plain text — either works. Compression is detected from the file's own bytes rather than a header, because a CI job that gzips but can't set Content-Encoding is common, and so is a header that claims gzip over plain text. Only the last 2,000 lines (up to 500 KB) are kept; the end of a build log is the part that explains it.

Read the full README on GitHub →

Releases

TagPublishedAssetDownloads
v1.1.0 Aug 6, 2026 code-builder-1.1.0.zip 0