• Skip to secondary menu
  • Skip to main content
  • Skip to primary sidebar
  • Home
  • Projects
  • Products
  • Themes
  • Tools
  • Request for Quote

Vengala Vinay

Having 12+ Years of Experience in Software Development

  • Home
  • WordPress
  • PHP
    • Codeigniter
  • Django
  • Magento
  • Selenium
  • Server
Home » Automating CI/CD Workflows for Enterprise Full Site Editing (FSE) Block Themes and theme.json in Legacy Core PHP Implementations

Automating CI/CD Workflows for Enterprise Full Site Editing (FSE) Block Themes and theme.json in Legacy Core PHP Implementations

Establishing a Robust CI/CD Pipeline for FSE Block Themes

Automating the deployment of Full Site Editing (FSE) block themes, especially those incorporating complex `theme.json` configurations and targeting legacy Core PHP implementations, presents unique challenges. This post details a production-ready CI/CD strategy leveraging GitHub Actions, Docker, and advanced WordPress CLI (WP-CLI) techniques to ensure consistent, reliable deployments.

Phase 1: Local Development and Linting

Before any code is committed, a rigorous local development environment is paramount. This includes automated checks for code style, syntax errors, and theme validation. We’ll integrate these into a pre-commit hook and a CI pipeline stage.

Pre-commit Hooks with ESLint and Stylelint

For JavaScript and CSS within your block theme, enforcing coding standards is crucial. We’ll use ESLint for JavaScript and Stylelint for CSS. These can be integrated via Husky and lint-staged for automated execution on commit.

`package.json` Configuration

Ensure your `package.json` includes the necessary dev dependencies and scripts:

{
  "name": "my-fse-theme",
  "version": "1.0.0",
  "scripts": {
    "lint:js": "eslint js/",
    "lint:css": "stylelint \"**/*.css\"",
    "lint:php": "phpcs --standard=WordPress-Core --extensions=php src/",
    "validate:theme": "wp theme validate --path=/path/to/wordpress/root"
  },
  "devDependencies": {
    "@wordpress/eslint-plugin": "^10.0.0",
    "eslint": "^8.0.0",
    "husky": "^8.0.0",
    "lint-staged": "^13.0.0",
    "stylelint": "^14.0.0",
    "stylelint-config-standard": "^28.0.0",
    "phpcs": "^3.0.0"
  },
  "husky": {
    "hooks": {
      "pre-commit": "lint-staged"
    }
  },
  "lint-staged": {
    "*.{js,jsx,ts,tsx}": [
      "eslint --fix"
    ],
    "*.{css,scss,sass}": [
      "stylelint --fix"
    ],
    "*.php": [
      "phpcs --standard=WordPress-Core --extensions=php"
    ]
  }
}

Installing Dependencies and Husky

After setting up `package.json`, install dependencies and initialize Husky:

npm install
npx husky install

PHP Code Sniffer for PHP Linting

For PHP code, we’ll leverage PHP Code Sniffer (PHPCS) with the WordPress Coding Standards. This ensures your PHP files adhere to WordPress’s established best practices.

Installing PHPCS and WordPress Standards

If not already installed, use Composer:

composer require --dev squizlabs/php_codesniffer wp-coding-standards/wpcs

Then, register the WordPress standards:

phpcs --config-set installed_paths vendor/wp-coding-standards/wpcs/

Theme Validation with WP-CLI

WP-CLI’s `theme validate` command is indispensable for checking `theme.json` and other theme structure issues.

wp theme validate --path=/path/to/your/wordpress/installation

Phase 2: CI Pipeline Setup with GitHub Actions

We’ll construct a GitHub Actions workflow to automate these checks on every push and pull request. This workflow will use a Docker container to provide a consistent WordPress environment.

Workflow File: `.github/workflows/ci.yml`

This YAML file defines the CI stages:

name: CI Pipeline

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

jobs:
  build:
    runs-on: ubuntu-latest
    container:
      image: wordpress:php8.1-apache # Or your preferred PHP/Apache version
      ports:
        - 80:80
      volumes:
        - wordpress_data:/var/www/html

    steps:
    - name: Checkout code
      uses: actions/checkout@v3

    - name: Setup PHP
      uses: shivammathur/setup-php@v2
      with:
        php-version: '8.1' # Match container version
        extensions: gd, imagick, mbstring, zip, intl
        coverage: none

    - name: Install Node.js and npm
      uses: actions/setup-node@v3
      with:
        node-version: '18'

    - name: Install Composer dependencies
      run: composer install --prefer-dist --no-progress --no-suggest

    - name: Install npm dependencies
      run: npm install

    - name: Lint JavaScript
      run: npm run lint:js

    - name: Lint CSS
      run: npm run lint:css

    - name: Lint PHP
      run: npm run lint:php

    - name: Setup WordPress environment (WP-CLI)
      run: |
        # Wait for Apache to start (basic check)
        sleep 10
        # Install WordPress core (if not present in image)
        if [ ! -f /var/www/html/wp-load.php ]; then
          wp core download --path=/var/www/html --allow-root
          wp config create --dbname=wordpress --dbuser=root --dbpass=root --dbhost=localhost --path=/var/www/html --allow-root
          wp db create --path=/var/www/html --allow-root
          wp core install --url=http://localhost --title="Test Site" --admin_user=admin --admin_password=password [email protected] --path=/var/www/html --allow-root
        fi
        # Install theme
        wp theme install ./ --activate --path=/var/www/html --allow-root

    - name: Validate Theme and theme.json
      run: |
        # Ensure WP-CLI can access the theme directory
        # The theme is installed in the previous step, so its path is relative to WP root
        wp theme validate --path=/var/www/html

    - name: Run WordPress Unit Tests (Optional but Recommended)
      # This step requires a more complex setup with WP_TESTS_DIR and a database
      # See WordPress Core development documentation for details
      # run: |
      #   # ... setup for WP_TESTS_DIR and database ...
      #   wp core unit-tests run --path=/var/www/html

    - name: Build Theme Assets (if applicable)
      # If your theme uses a build process for JS/CSS (e.g., Webpack, Gulp)
      # run: npm run build

    - name: Upload Theme Artifacts (Optional)
      # If you need to package the theme for distribution
      # uses: actions/upload-artifact@v3
      # with:
      #   name: theme-package
      #   path: ./dist/  # Or wherever your built theme is

  # Add deployment jobs here for staging/production
  # deploy_staging:
  #   needs: build
  #   runs-on: ubuntu-latest
  #   if: github.ref == 'refs/heads/main' && github.event_name == 'push'
  #   steps:
  #     - name: Deploy to Staging
  #       # ... deployment steps using SSH, rsync, or a deployment service ...

Explanation of Key Steps

  • Containerization: The `wordpress:php8.1-apache` image provides a pre-configured WordPress environment, simplifying setup. Volumes ensure data persistence if needed, though for CI, ephemeral environments are common.
  • PHP and Node.js Setup: Explicitly sets up the required PHP and Node.js versions.
  • Dependency Installation: Installs both Composer and npm packages.
  • Linting: Executes the defined linting scripts.
  • WordPress Environment Setup: This is a critical part. It downloads WordPress core (if not already in the image), creates a database, installs WordPress, and then installs and activates your theme. This ensures the theme is tested within a functional WordPress context. The `sleep 10` is a rudimentary wait for Apache; more robust health checks might be needed in complex scenarios.
  • Theme Validation: Runs `wp theme validate` to catch structural and `theme.json` errors.
  • Artifact Upload: An optional step to save built theme files.

Phase 3: Advanced `theme.json` and Block Validation

Beyond basic linting, ensuring the integrity and correctness of `theme.json` and custom blocks is vital. This involves schema validation and potentially custom validation scripts.

Schema Validation for `theme.json`

The WordPress core team maintains a JSON schema for `theme.json`. We can leverage this in our CI pipeline to validate the structure and types of our `theme.json` file.

Obtaining the Schema

The schema is typically found within the WordPress core repository. For CI, it’s often best to download a specific version or reference it directly if available via a stable URL. As of WordPress 6.2, the schema is part of the core distribution. A common approach is to fetch it from a known stable location or include it in your repository.

Using a JSON Schema Validator (e.g., `ajv-cli`)

We can add a JSON schema validator to our `devDependencies` and create a script to run the validation.

npm install --save-dev ajv-cli

Add a script to `package.json`:

"scripts": {
  // ... other scripts
  "validate:themejson": "ajv validate -s /path/to/wordpress/core/wp-content/themes/your-theme/theme.json -d /path/to/wordpress/core/wp-content/themes/your-theme/theme.json"
}

Note: The above `ajv-cli` example is simplified. A more robust approach would involve fetching the official WordPress `theme.json` schema and validating against that. You might need to adjust paths or download the schema dynamically within your CI script.

Custom Block Validation Scripts

For custom blocks, you might have specific validation logic beyond what `theme.json` or standard linters cover. This could involve checking attribute types, default values, or dependencies.

Example: Python Script for Block Validation

Create a Python script (e.g., `scripts/validate_blocks.py`) to parse block metadata and perform checks. This script would need to be executed within the CI environment.

import json
import os
import sys

def validate_block_attributes(block_json_path):
    try:
        with open(block_json_path, 'r') as f:
            block_data = json.load(f)
    except FileNotFoundError:
        print(f"Error: Block JSON not found at {block_json_path}", file=sys.stderr)
        return False
    except json.JSONDecodeError:
        print(f"Error: Invalid JSON in {block_json_path}", file=sys.stderr)
        return False

    is_valid = True
    if 'attributes' in block_data:
        for attr_name, attr_config in block_data['attributes'].items():
            # Example validation: Ensure 'type' is present and is a string
            if 'type' not in attr_config:
                print(f"Validation Error in {block_json_path}: Attribute '{attr_name}' is missing 'type'.", file=sys.stderr)
                is_valid = False
            elif not isinstance(attr_config['type'], str):
                print(f"Validation Error in {block_json_path}: Attribute '{attr_name}' has non-string 'type'.", file=sys.stderr)
                is_valid = False
            # Add more specific attribute validations here (e.g., allowed types, default values)

    return is_valid

def main():
    blocks_dir = 'src/blocks' # Assuming blocks are in src/blocks
    all_valid = True

    if not os.path.isdir(blocks_dir):
        print(f"Warning: Blocks directory '{blocks_dir}' not found.", file=sys.stderr)
        return

    for root, _, files in os.walk(blocks_dir):
        for file in files:
            if file == 'block.json':
                block_json_path = os.path.join(root, file)
                if not validate_block_attributes(block_json_path):
                    all_valid = False

    if not all_valid:
        sys.exit(1) # Fail the CI job
    else:
        print("All custom blocks validated successfully.")

if __name__ == "__main__":
    main()

Integrate this script into your CI workflow:

    - name: Validate Custom Blocks
      run: |
        python scripts/validate_blocks.py

Phase 4: Deployment Strategies

Once the CI pipeline passes, the theme is ready for deployment. For enterprise environments, this typically involves staging and production environments.

Staging Environment Deployment

Automate deployment to a staging server using SSH, rsync, or a dedicated deployment tool. This allows for final testing before production.

Example: SSH and Rsync Deployment

You’ll need SSH keys configured for GitHub Actions and access to your staging server. Store sensitive information like SSH keys and server IPs as GitHub Secrets.

deploy_staging:
  needs: build
  runs-on: ubuntu-latest
  if: github.ref == 'refs/heads/main' && github.event_name == 'push' # Deploy only on push to main
  steps:
    - name: Checkout code
      uses: actions/checkout@v3

    - name: Setup SSH Key
      uses: webfactory/[email protected]
      with:
        ssh-private-key: ${{ secrets.STAGING_SSH_PRIVATE_KEY }}

    - name: Add SSH Host Key
      run: ssh-keyscan ${{ secrets.STAGING_SERVER_IP }} >> ~/.ssh/known_hosts

    - name: Deploy Theme to Staging
      run: |
        rsync -avz --delete \
          --exclude '.git' \
          --exclude '.github' \
          --exclude 'node_modules' \
          --exclude 'vendor' \
          . ${{ secrets.STAGING_SSH_USER }}@${{ secrets.STAGING_SERVER_IP }}:/path/to/your/staging/wordpress/wp-content/themes/my-fse-theme/
        # Optional: Run WP-CLI commands on staging server
        ssh ${{ secrets.STAGING_SSH_USER }}@${{ secrets.STAGING_SERVER_IP }} "wp cache flush --path=/path/to/your/staging/wordpress"
        ssh ${{ secrets.STAGING_SSH_USER }}@${{ secrets.STAGING_SERVER_IP }} "wp theme activate my-fse-theme --path=/path/to/your/staging/wordpress"

Production Environment Deployment

Production deployments should be highly controlled, often requiring manual approval or a separate trigger. The process is similar to staging but targets the production environment.

Manual Approval Gate

GitHub Actions allows for environments with manual approval steps. Configure an environment in your GitHub repository settings and reference it in the workflow.

deploy_production:
  needs: build # Or needs: deploy_staging if you want sequential deployment
  runs-on: ubuntu-latest
  environment:
    name: production
    url: https://your-production-site.com
  if: github.ref == 'refs/heads/main' && github.event_name == 'push' # Deploy only on push to main
  steps:
    - name: Checkout code
      uses: actions/checkout@v3

    - name: Setup SSH Key
      uses: webfactory/[email protected]
      with:
        ssh-private-key: ${{ secrets.PRODUCTION_SSH_PRIVATE_KEY }}

    - name: Add SSH Host Key
      run: ssh-keyscan ${{ secrets.PRODUCTION_SERVER_IP }} >> ~/.ssh/known_hosts

    - name: Deploy Theme to Production
      run: |
        rsync -avz --delete \
          --exclude '.git' \
          --exclude '.github' \
          --exclude 'node_modules' \
          --exclude 'vendor' \
          . ${{ secrets.PRODUCTION_SSH_USER }}@${{ secrets.PRODUCTION_SERVER_IP }}:/path/to/your/production/wordpress/wp-content/themes/my-fse-theme/
        ssh ${{ secrets.PRODUCTION_SSH_USER }}@${{ secrets.PRODUCTION_SERVER_IP }} "wp cache flush --path=/path/to/your/production/wordpress"
        ssh ${{ secrets.PRODUCTION_SSH_USER }}@${{ secrets.PRODUCTION_SERVER_IP }} "wp theme activate my-fse-theme --path=/path/to/your/production/wordpress"

Advanced Diagnostics and Troubleshooting

When things go wrong, systematic diagnostics are key. Here are common failure points and how to address them.

CI Job Failures

  • Check Logs: The first step is always to examine the detailed logs provided by GitHub Actions. Look for specific error messages from linters, WP-CLI, or build scripts.
  • Environment Mismatch: Ensure the PHP version in `setup-php` matches the Docker image and your local development environment. Similarly, Node.js versions can cause build failures.
  • Dependency Issues: `npm install` or `composer install` failures often point to network issues, incompatible package versions, or corrupted lock files. Try clearing caches (`npm cache clean –force`, `composer clear-cache`) and re-running.
  • WP-CLI Path Errors: Ensure the `–path` argument for WP-CLI commands correctly points to the WordPress root directory within the container.
  • Permissions: In Docker containers, file permissions can be tricky. The `–allow-root` flag for WP-CLI is often necessary but should be used judiciously. Ensure the user running commands has write access to necessary directories.

Theme Validation Errors

wp theme validate errors typically relate to `theme.json` syntax, missing required files (like `style.css` or `index.php`), or incorrect theme headers.

Deployment Failures

  • SSH Connection Errors: Verify SSH keys are correctly added to GitHub Secrets and that the server’s `authorized_keys` file is properly configured. Check firewall rules.
  • Rsync Permissions: Ensure the SSH user has write permissions to the target theme directory on the server.
  • WP-CLI Commands on Remote Server: If `wp cache flush` or `wp theme activate` fail on the remote server, log in manually via SSH and run the commands to debug. Ensure WP-CLI is installed and accessible on the remote server.

Conclusion

Implementing a comprehensive CI/CD pipeline for FSE block themes requires a multi-faceted approach. By integrating local development checks, robust CI stages with containerized environments, and controlled deployment strategies, you can significantly improve the quality, consistency, and reliability of your WordPress theme development workflow. The key is automation at every stage, from code linting to production deployment, with clear diagnostic pathways for troubleshooting.

Primary Sidebar

A little about the Author

Having 12+ Years of Experience in Software Development, Vinay is a principal software architect, senior systems engineer, and elite technical consultant. He specializes in bespoke PHP/WordPress development, high-performance Magento 2 & Shopify architectures, custom plugin/theme development from scratch, and legacy code modernization (including VB6, VB.NET, PyQt, and Crystal Reports). Known for solving complex database bottlenecks, speed optimization (Core Web Vitals), and advanced security code auditing, Vinay engineers production-ready systems designed to scale under heavy concurrent load conditions.



Chat on WhatsApp

Recent Posts

  • Leveraging PHP 8 JIT and AWS Lambda for High-Performance, Serverless WordPress REST API Backends
  • Beyond the Basics: Leveraging PHP 8.3’s JIT Compiler and Fibers for High-Concurrency Laravel Applications
  • Zero-Downtime Deployments with Docker, Laravel, and AWS ECS: A Deep Dive into Blue/Green Strategies
  • Leveraging PHP 9’s JIT and Concurrency Features for High-Performance Laravel Microservices on AWS ECS
  • Leveraging PHP 8.3 JIT and OPcache for Sub-Millisecond API Response Times: A Practical Deep Dive

Categories

  • apache (1)
  • Business & Monetization (390)
  • Centos (4)
  • Comparisons & Decision Making (55)
  • Debian (2)
  • Debugging & Troubleshooting (664)
  • Desktop Applications (14)
  • DevOps (11)
  • DevOps & Cloud Scaling (962)
  • Django (1)
  • Laravel (6)
  • Migration & Architecture (192)
  • Mobile Applications (24)
  • MySQL (1)
  • Performance & Optimization (873)
  • PHP (14)
  • PHP Development (49)
  • Plugins & Themes (244)
  • Programming Languages (10)
  • Python (20)
  • Ruby on Rails (1)
  • Security & Compliance (650)
  • SEO & Growth (492)
  • Server (118)
  • Softwares (1)
  • Ubuntu (9)
  • Uncategorized (17)
  • VB6 & VB.NET (8)
  • Web Applications & Frontend (19)
  • Web Assembly (Wasm) (2)
  • WordPress (24)
  • WordPress Plugin Development (728)
  • WordPress Theme Development (357)

Recent Posts

  • Leveraging PHP 8 JIT and AWS Lambda for High-Performance, Serverless WordPress REST API Backends
  • Beyond the Basics: Leveraging PHP 8.3's JIT Compiler and Fibers for High-Concurrency Laravel Applications
  • Zero-Downtime Deployments with Docker, Laravel, and AWS ECS: A Deep Dive into Blue/Green Strategies

Top Categories

  • DevOps & Cloud Scaling (962)
  • Performance & Optimization (873)
  • WordPress Plugin Development (728)
  • Debugging & Troubleshooting (664)
  • Security & Compliance (650)
  • SEO & Growth (492)

Our Products

  • ERP & LMS Systems (4)
  • Directories & Marketplaces (4)
  • Healthcare Portals (3)
  • Point of Sale (POS) (2)
  • E-Commerce Engines (2)

Our Services

  • E-Commerce Development (10)
  • WordPress Development (8)
  • Python & Desktop GUI (7)
  • General Consulting (7)
  • Legacy Modernization (5)
  • Mobile App Development (4)

Copyright © 2026 · Vinay Vengala