WooCommerce Headless Blueprint
Purpose
Section titled “Purpose”Use this SOP when a human needs to create a new headless WooCommerce project for a client using the GETQUICK three-repository pattern.
The workflow creates:
- A parent workspace repository under
Quick-Release/<client-slug>. - A WordPress admin repository under
Quick-Release/<client-slug>-admin. - An Astro frontend repository under
Quick-Release/<client-slug>-fe.
The parent repository records the admin and frontend repositories as Git submodules. WordPress deploys to Ploi at admin.<client-domain>, and Astro deploys to Cloudflare Workers.
Context
Section titled “Context”This blueprint follows the existing GETQUICK headless WordPress/WooCommerce workspace shape:
- The parent repo coordinates local development and submodule versions.
- The admin repo contains Bedrock WordPress, DDEV local development, WooCommerce, GraphQL/API configuration, and Ploi deployment configuration.
- The frontend repo contains the Astro storefront, Cloudflare Workers deployment configuration, and WordPress/WooCommerce data integration.
Use the current internal example repositories as the source pattern, but rename everything to generic client values before committing the new project.
Supporting SOPs:
- Cloudflare domain registration:
/cloudflare/register-a-domain-with-cloudflare/ - Ploi API reference:
/ploi-io/ploi-api-reference/ - Ploi auth config:
/ploi-io/auth-config/ - Agent domain registration policy:
/agents/allow-agents-to-register-domains/
Official references:
- DDEV installation:
https://docs.ddev.com/en/stable/users/install/ddev-installation/ - GitHub CLI:
https://github.com/cli/cli - Cloudflare Wrangler:
https://developers.cloudflare.com/workers/wrangler/commands/general/
Outcome
Section titled “Outcome”After the procedure is complete:
- Three private GitHub repositories exist under
Quick-Release. - The parent repository includes the admin and frontend repositories as submodules.
- The admin repository can run WordPress locally with DDEV and can deploy to Ploi.
- The frontend repository can run Astro locally and deploy to Cloudflare Workers.
- Required GitHub secrets and variables are configured for Ploi and Cloudflare deployments.
- The production admin hostname is
admin.<client-domain>. - The production storefront hostname is ready for the chosen client domain.
Set project variables
Section titled “Set project variables”Run this first and edit only the values on the right side:
export GITHUB_ORG="Quick-Release"export CLIENT_SLUG="clientname"export CLIENT_DOMAIN="clientdomain.tld"export MAIN_REPO="${CLIENT_SLUG}"export ADMIN_REPO="${CLIENT_SLUG}-admin"export FE_REPO="${CLIENT_SLUG}-fe"export ADMIN_HOST="admin.${CLIENT_DOMAIN}"export WP_ADMIN_USER="admin"export WP_ADMIN_PASSWORD="change-this-password"export WP_ADMIN_EMAIL="admin@${CLIENT_DOMAIN}"export WORKDIR="${HOME}/workspaces/${CLIENT_SLUG}"export SOURCE_MAIN_REPO="<approved-parent-example>"export SOURCE_ADMIN_REPO="<approved-admin-example>"export SOURCE_FE_REPO="<approved-frontend-example>"Use lowercase kebab-case for CLIENT_SLUG. Do not include the customer legal name if it should not appear in GitHub URLs.
Set the SOURCE_* variables to the current approved internal example repositories before running the copy step.
Install or update required CLIs on macOS
Section titled “Install or update required CLIs on macOS”Use this path for macOS workstations with Homebrew:
brew updatebrew install git gh curl jq node composer ddev/ddev/ddev mkcertbrew install --cask dockermkcert -installcorepack enablecorepack prepare pnpm@latest --activatenpm install -g wrangler@latest
git --versiongh --versioncurl --versionjq --versiondocker versionddev --versionmkcert -help >/dev/nullnode --versionpnpm --versioncomposer --versionwrangler --versionStart Docker Desktop before running DDEV commands.
Install or update required CLIs on Ubuntu or Debian
Section titled “Install or update required CLIs on Ubuntu or Debian”Use this path for Ubuntu or Debian workstations:
sudo apt-get updatesudo apt-get install -y git curl jq ca-certificates gnupg lsb-release unzip
# Docker providersudo install -m 0755 -d /etc/apt/keyringscurl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpgecho \ "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \ $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \ sudo tee /etc/apt/sources.list.d/docker.list >/dev/nullsudo apt-get updatesudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-pluginsudo usermod -aG docker "$USER"
# GitHub CLIsudo mkdir -p -m 755 /etc/apt/keyringscurl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | \ sudo tee /etc/apt/keyrings/githubcli-archive-keyring.gpg >/dev/nullsudo chmod go+r /etc/apt/keyrings/githubcli-archive-keyring.gpgecho "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | \ sudo tee /etc/apt/sources.list.d/github-cli.list >/dev/nullsudo apt-get updatesudo apt-get install -y gh
# DDEV and mkcertcurl -fsSL https://ddev.com/install.sh | bashmkcert -install
# Node, pnpm, Composer, Wranglercurl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -sudo apt-get install -y nodejs composercorepack enablecorepack prepare pnpm@latest --activatesudo npm install -g wrangler@latest
git --versiongh --versioncurl --versionjq --versiondocker versionddev --versionmkcert -help >/dev/nullnode --versionpnpm --versioncomposer --versionwrangler --versionLog out and back in if Docker reports permission errors after adding the user to the docker group.
Authenticate CLIs
Section titled “Authenticate CLIs”Authenticate GitHub and Cloudflare:
gh auth logingh auth status
wrangler loginwrangler whoamiCreate the Ploi API token and GitHub secrets using the Ploi Auth Config SOP:
https://sop.getquick.io/ploi-io/auth-config/At minimum, plan for:
PLOI_API_TOKENPLOI_SERVER_IDPLOI_SITE_IDPLOI_USER_AGENTCreate the private GitHub repositories
Section titled “Create the private GitHub repositories”Create all three repositories under Quick-Release:
gh repo create "${GITHUB_ORG}/${MAIN_REPO}" --private --confirmgh repo create "${GITHUB_ORG}/${ADMIN_REPO}" --private --confirmgh repo create "${GITHUB_ORG}/${FE_REPO}" --private --confirmConfirm they exist:
gh repo view "${GITHUB_ORG}/${MAIN_REPO}" --json name,visibility,urlgh repo view "${GITHUB_ORG}/${ADMIN_REPO}" --json name,visibility,urlgh repo view "${GITHUB_ORG}/${FE_REPO}" --json name,visibility,urlCreate local working copies from the approved examples
Section titled “Create local working copies from the approved examples”Use the current approved internal examples as source workspaces. Keep the source repositories unchanged and copy into fresh target folders.
mkdir -p "$WORKDIR"cd "$WORKDIR"
gh repo clone "${GITHUB_ORG}/${MAIN_REPO}" "${MAIN_REPO}"gh repo clone "${GITHUB_ORG}/${ADMIN_REPO}" "${ADMIN_REPO}"gh repo clone "${GITHUB_ORG}/${FE_REPO}" "${FE_REPO}"
mkdir -p "${WORKDIR}/_sources"cd "${WORKDIR}/_sources"gh repo clone "${GITHUB_ORG}/${SOURCE_MAIN_REPO}" parent-examplegh repo clone "${GITHUB_ORG}/${SOURCE_ADMIN_REPO}" admin-examplegh repo clone "${GITHUB_ORG}/${SOURCE_FE_REPO}" frontend-exampleCopy source files into the new repositories without copying .git directories:
rsync -a --exclude ".git" --exclude "node_modules" --exclude "vendor" --exclude ".ddev/.global_commands" \ "${WORKDIR}/_sources/parent-example/" "${WORKDIR}/${MAIN_REPO}/"
rsync -a --exclude ".git" --exclude "node_modules" --exclude "vendor" \ "${WORKDIR}/_sources/admin-example/" "${WORKDIR}/${ADMIN_REPO}/"
rsync -a --exclude ".git" --exclude "node_modules" --exclude "dist" --exclude ".wrangler" \ "${WORKDIR}/_sources/frontend-example/" "${WORKDIR}/${FE_REPO}/"Replace example names with client names before committing:
cd "$WORKDIR"grep -R "<example-client>" "${MAIN_REPO}" "${ADMIN_REPO}" "${FE_REPO}" || true
find "${MAIN_REPO}" "${ADMIN_REPO}" "${FE_REPO}" -type f \ -not -path "*/.git/*" \ -not -path "*/node_modules/*" \ -not -path "*/vendor/*" \ -print0 | \ xargs -0 perl -pi -e "s/<example-client>/${CLIENT_SLUG}/g; s/<example-domain>/${CLIENT_DOMAIN}/g; s/admin\\.<example-domain>/${ADMIN_HOST}/g"If source examples contain project-specific names that are not covered by these placeholders, replace them manually before the first commit.
Configure the parent workspace repository
Section titled “Configure the parent workspace repository”Add the admin and frontend repositories as submodules:
cd "${WORKDIR}/${MAIN_REPO}"rm -rf "${ADMIN_REPO}" "${FE_REPO}"
git submodule add "git@github.com:${GITHUB_ORG}/${ADMIN_REPO}.git" "${ADMIN_REPO}"git submodule add "git@github.com:${GITHUB_ORG}/${FE_REPO}.git" "${FE_REPO}"
git submodule statusUpdate parent workspace references so scripts point at the generic submodule names:
grep -R "<admin-submodule>" . || truegrep -R "<frontend-submodule>" . || trueExpected final parent layout:
<client-slug>/├── AGENTS.md├── README.md├── package.json├── .gitmodules├── <client-slug>-admin/└── <client-slug>-fe/Commit the parent workspace:
git add -Agit commit -m "Initial headless WooCommerce workspace"git push -u origin mainConfigure WordPress admin
Section titled “Configure WordPress admin”Set up the Bedrock/DDEV admin repository:
cd "${WORKDIR}/${ADMIN_REPO}"
cp .env.example .env 2>/dev/null || trueperl -pi -e "s|^WP_HOME=.*|WP_HOME=https://${ADMIN_HOST}|; s|^WP_SITEURL=.*|WP_SITEURL=https://${ADMIN_HOST}/wp|" .env
ddev config --project-name "${ADMIN_REPO}" --project-type wordpress --docroot web --php-version 8.3ddev startddev composer installInstall WordPress locally if the Bedrock setup does not already include a database:
ddev wp core install \ --url="https://${ADMIN_REPO}.ddev.site" \ --title="${CLIENT_SLUG} Admin" \ --admin_user="${WP_ADMIN_USER}" \ --admin_password="${WP_ADMIN_PASSWORD}" \ --admin_email="${WP_ADMIN_EMAIL}" \ --skip-emailInstall or activate required WordPress components for headless WooCommerce:
ddev wp plugin activate woocommerce || ddev wp plugin install woocommerce --activateddev wp plugin activate wp-graphql || ddev wp plugin install wp-graphql --activateddev wp rewrite structure '/%postname%/' --hardddev wp rewrite flush --hardCommit and push the admin repo:
git add -Agit commit -m "Initial Bedrock WooCommerce admin"git push -u origin mainConfigure Ploi for WordPress admin
Section titled “Configure Ploi for WordPress admin”In Ploi:
- Create or choose the server.
- Create a site for
admin.${CLIENT_DOMAIN}. - Set the repository to
git@github.com:${GITHUB_ORG}/${ADMIN_REPO}.git. - Set the deploy branch to
main. - Configure the site as a Bedrock WordPress project.
- Add environment variables from the admin
.env, replacing local values with production values. - Add the database credentials Ploi created for the site.
- Configure SSL for
admin.${CLIENT_DOMAIN}. - Deploy once from Ploi.
Add GitHub secrets and variables for automation:
cd "${WORKDIR}/${ADMIN_REPO}"
gh secret set PLOI_API_TOKEN --repo "${GITHUB_ORG}/${ADMIN_REPO}"gh variable set PLOI_SERVER_ID --repo "${GITHUB_ORG}/${ADMIN_REPO}" --body "<ploi-server-id>"gh variable set PLOI_SITE_ID --repo "${GITHUB_ORG}/${ADMIN_REPO}" --body "<ploi-site-id>"gh variable set PLOI_USER_AGENT --repo "${GITHUB_ORG}/${ADMIN_REPO}" --body "${ADMIN_REPO}-github-actions"Configure Astro frontend
Section titled “Configure Astro frontend”Set up the frontend repository:
cd "${WORKDIR}/${FE_REPO}"
pnpm installpnpm exec wrangler init --from-dash "${FE_REPO}" || truepnpm exec wrangler typesCreate or update the frontend environment file:
cat > .env.example <<EOFPUBLIC_SITE_URL=https://${CLIENT_DOMAIN}WORDPRESS_URL=https://${ADMIN_HOST}WORDPRESS_GRAPHQL_URL=https://${ADMIN_HOST}/graphqlWOOCOMMERCE_STORE_URL=https://${ADMIN_HOST}EOF
cp .env.example .envConfirm the frontend can build:
pnpm buildCommit and push the frontend repo:
git add -Agit commit -m "Initial Astro WooCommerce frontend"git push -u origin mainConfigure Cloudflare Workers for Astro
Section titled “Configure Cloudflare Workers for Astro”Register or connect the domain with the Cloudflare domain SOP if needed:
https://sop.getquick.io/cloudflare/register-a-domain-with-cloudflare/Deploy the frontend:
cd "${WORKDIR}/${FE_REPO}"pnpm buildpnpm exec wrangler deployIf the Worker uses secrets, set them with Wrangler:
pnpm exec wrangler secret put WORDPRESS_GRAPHQL_URLpnpm exec wrangler secret put WOOCOMMERCE_CONSUMER_KEYpnpm exec wrangler secret put WOOCOMMERCE_CONSUMER_SECRETOnly set WooCommerce API credentials if the frontend requires authenticated server-side WooCommerce API access. Prefer public GraphQL or Store API data when possible.
Update parent submodule pointers
Section titled “Update parent submodule pointers”After the admin and frontend repos are pushed, update the parent submodule SHAs:
cd "${WORKDIR}/${MAIN_REPO}"git submodule update --remote --mergegit statusgit add "${ADMIN_REPO}" "${FE_REPO}" .gitmodulesgit commit -m "Bump initial admin and frontend submodules"git pushValidation
Section titled “Validation”Validate GitHub repositories:
gh repo view "${GITHUB_ORG}/${MAIN_REPO}" --json name,visibility,urlgh repo view "${GITHUB_ORG}/${ADMIN_REPO}" --json name,visibility,urlgh repo view "${GITHUB_ORG}/${FE_REPO}" --json name,visibility,urlValidate submodules:
cd "${WORKDIR}/${MAIN_REPO}"git submodule statusgit config --file .gitmodules --get-regexp pathExpected result: the admin and frontend submodules are present and have pinned SHAs.
Validate WordPress locally:
cd "${WORKDIR}/${ADMIN_REPO}"ddev describeddev wp option get homeddev wp plugin status woocommerceddev wp plugin status wp-graphqlcurl -I "https://${ADMIN_REPO}.ddev.site"Validate Ploi readiness:
curl -fsS https://ploi.io/api/servers \ -H "Authorization: Bearer $PLOI_API_TOKEN" \ -H "Accept: application/json" \ -H "Content-Type: application/json" \ -H "User-Agent: ${ADMIN_REPO}-smoke-test"Validate Astro and Cloudflare:
cd "${WORKDIR}/${FE_REPO}"pnpm buildpnpm exec wrangler whoamipnpm exec wrangler deploy --dry-runValidate final DNS and HTTPS:
dig A "${CLIENT_DOMAIN}"dig CNAME "www.${CLIENT_DOMAIN}"dig A "${ADMIN_HOST}"curl -I "https://${CLIENT_DOMAIN}"curl -I "https://${ADMIN_HOST}"Expected result:
https://${ADMIN_HOST}reaches the Ploi WordPress admin site.https://${CLIENT_DOMAIN}reaches the Astro frontend on Cloudflare Workers.- The parent repo records the exact admin and frontend submodule commits.
Operational notes for agents
Section titled “Operational notes for agents”Use this article when a user asks for a new WooCommerce headless stack, a three-repository WordPress/Astro workspace, or a GETQUICK storefront blueprint.
Do not place this workflow under the Agents category. It is a human operational blueprint.
Retrieve current docs before executing provider-specific steps:
- GitHub CLI:
https://github.com/cli/cli - DDEV:
https://docs.ddev.com/en/stable/users/install/ddev-installation/ - Cloudflare Wrangler:
https://developers.cloudflare.com/workers/wrangler/commands/general/ - Ploi API:
https://developers.ploi.io/
Never commit secrets. Use GitHub Secrets, Wrangler secrets, Ploi environment variables, or local untracked .env files.
Important search terms: WooCommerce headless, Bedrock, DDEV, Ploi, Cloudflare Workers, Astro frontend, GitHub submodules, WordPress admin, storefront.
Troubleshooting
Section titled “Troubleshooting”- If
gh repo createfails, rungh auth statusand confirm the user has permission to create repositories underQuick-Release. - If submodule clone fails, confirm SSH access to all private repositories.
- If DDEV fails to start, confirm Docker is running and the current user can access Docker.
- If
ddev composer installfails, check Composer authentication for private packages. - If WordPress install fails, confirm the Bedrock
.envdatabase values match DDEV. - If WooCommerce or WPGraphQL activation fails, confirm the packages are installed or add them through Composer/WP-CLI according to the admin repo pattern.
- If Ploi deployment fails, confirm repository access, deploy branch, production
.env, database credentials, and Ploi token scopes. - If Wrangler deployment fails, run
wrangler whoami, confirm the Cloudflare account, and checkwrangler.jsonc. - If the frontend cannot fetch WordPress data, verify
WORDPRESS_GRAPHQL_URL, CORS, SSL, and that the admin host is reachable.