diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e71ff78..ce5267a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,112 +1,24 @@ -name: CI — Lint & Test - -# Runs on every PR and every push to main. -# Three jobs in parallel: -# 1. PHP Lint — syntax check across supported PHP versions -# 2. PHPCS — WordPress coding standards (non-blocking during theme rollout) -# 3. PHPUnit — runs the theme's test suite against the WordPress test framework +name: CI +# Thin caller — delegates all jobs to the shared reusable workflow. +# Must include workflow_call so deploy.yml can gate on this workflow. on: + pull_request: {} push: branches: [main] - pull_request: - branches: [main] + workflow_call: {} +# Required by the reusable phpcs job which commits phpcbf auto-fixes back +# to the PR branch. GitHub enforces that callers declare at least the same +# permissions as any job-level override in the called workflow. permissions: - contents: read + contents: write jobs: - php-lint: - name: PHP Lint (${{ matrix.php }}) - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - php: ['8.1', '8.2', '8.3'] - steps: - - uses: actions/checkout@v4 - - name: Setup PHP ${{ matrix.php }} - uses: shivammathur/setup-php@v2 - with: - php-version: ${{ matrix.php }} - coverage: none - - name: Syntax check all PHP files - run: | - set -e - find . -name '*.php' \ - -not -path './vendor/*' \ - -not -path './node_modules/*' \ - -not -path './.git/*' \ - -print0 | xargs -0 -n1 -P4 php -l > /dev/null - - phpcs: - name: PHPCS (WordPress standards) - runs-on: ubuntu-latest - continue-on-error: true - steps: - - uses: actions/checkout@v4 - - name: Setup PHP - uses: shivammathur/setup-php@v2 - with: - php-version: '8.1' - coverage: none - tools: composer:v2 - - name: Install dependencies - run: composer install --no-progress --no-interaction --prefer-dist - - name: Run PHPCS - run: vendor/bin/phpcs --standard=.phpcs.xml.dist - - phpunit: - name: PHPUnit (PHP ${{ matrix.php }}, WP ${{ matrix.wp }}) - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - php: ['8.1', '8.2', '8.3'] - wp: ['latest'] - services: - mysql: - image: mysql:8.0 - env: - MYSQL_ROOT_PASSWORD: root - MYSQL_DATABASE: wp_tests - ports: - - 3306:3306 - options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=5 - steps: - - uses: actions/checkout@v4 - - name: Install subversion - # ubuntu-latest no longer ships svn preinstalled. The WP test suite - # bootstrap script checks out develop.svn.wordpress.org via svn. - run: sudo apt-get update -qq && sudo apt-get install -y --no-install-recommends subversion - - name: Setup PHP ${{ matrix.php }} - uses: shivammathur/setup-php@v2 - with: - php-version: ${{ matrix.php }} - coverage: none - tools: composer:v2 - extensions: mysqli - - name: Install composer dependencies - run: composer install --no-progress --no-interaction --prefer-dist - - name: Wait for MySQL - run: | - for i in {1..30}; do - if mysqladmin ping -h 127.0.0.1 -P 3306 -u root -proot --silent; then - echo "MySQL is up"; break - fi - echo "Waiting for MySQL..."; sleep 2 - done - - name: Install WordPress test suite - env: - WP_TESTS_DIR: /tmp/wordpress-tests-lib - # Trailing slash matters: the bootstrap config substitutes this verbatim into ABSPATH, - # then concatenates 'wp-settings.php'. Without the slash you get '/tmp/wordpresswp-settings.php'. - WP_CORE_DIR: /tmp/wordpress/ - run: | - chmod +x bin/install-wp-tests.sh - # 6th arg = skip-database-creation: the MySQL service already created wp_tests via MYSQL_DATABASE env. - bin/install-wp-tests.sh wp_tests root root 127.0.0.1:3306 ${{ matrix.wp }} true - - name: Run PHPUnit - env: - WP_TESTS_DIR: /tmp/wordpress-tests-lib - run: vendor/bin/phpunit --colors=always + ci: + uses: peptiderepo/peptide-e2e/.github/workflows/ci.yml@main + with: + tests: wp-framework + has_js: true + line_limit_paths: inc + secrets: inherit diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index f9e72c4..f8da912 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -9,30 +9,16 @@ concurrency: cancel-in-progress: true jobs: - validate: - name: Validate PHP & JS - runs-on: ubuntu-latest - steps: - - name: Checkout code - uses: actions/checkout@v4 - - name: PHP Lint Check - run: | - find . -name "*.php" -not -path "./vendor/*" -not -path "./node_modules/*" -exec php -l {} \; | (grep -v "No syntax errors" || true) | head -20 - test ${PIPESTATUS[0]} -eq 0 - - name: Install PHPCS with WordPress standards - run: | - composer global config allow-plugins.dealerdirect/phpcodesniffer-composer-installer true - composer global require --dev squizlabs/php_codesniffer:"^3.0" wp-coding-standards/wpcs:"^3.0" phpcsstandards/phpcsutils:"^1.0" - - name: Run PHPCS (WordPress Core) - run: | - ~/.composer/vendor/bin/phpcs -s . || true # non-blocking during theme rollout - - name: JS Syntax Check - run: | - find assets/js -name "*.js" -exec node --check {} \; + # Gate deploy on the reusable CI (lint-php, phpcs, phpunit, file-size, lint-js). + # ci.yml exposes workflow_call so it can be used here without re-running a + # separate workflow — the call result satisfies the branch-protection context + # "ci / ci (lint-php (8.1))" etc. + ci: + uses: ./.github/workflows/ci.yml deploy: name: Deploy (shared pipeline) - needs: validate + needs: ci uses: peptiderepo/peptide-e2e/.github/workflows/deploy-app.yml@main with: target_path: wp-content/themes/peptide-starter diff --git a/CHANGELOG.md b/CHANGELOG.md index 592916e..9de7d3c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,30 @@ # Peptide Starter Theme - Changelog +## [2.3.0] - 2026-06-16 — Adopt estate CI standard + +### Changed + +- `.github/workflows/ci.yml`: Replaced per-repo CI jobs with a thin caller + delegating to `peptiderepo/peptide-e2e/.github/workflows/ci.yml@main` + (`tests: wp-framework`, `has_js: true`, `line_limit_paths: inc`). Added + `workflow_call` trigger so `deploy.yml` can gate on this workflow. +- `.github/workflows/deploy.yml`: Retired standalone `validate` job; deploy + now gates on the reusable CI via `uses: ./.github/workflows/ci.yml`. +- `composer.json`: `test` script now calls `vendor/bin/phpunit` explicitly + (was bare `phpunit`). +- `inc/helpers.php`: Split 311-line file at the nav-walker boundary; reduced + to 211 lines. + +### Added + +- `inc/nav-walker.php`: `Peptide_Starter_Nav_Walker` class and + `peptide_starter_primary_menu_fallback()` extracted from `inc/helpers.php` + (123 lines). Loaded in `functions.php` before `helpers.php`. +- `package.json` / `package-lock.json`: Minimal npm manifest so the reusable + `lint-js` job can run `npm ci` and then execute `npm run lint` (which runs + `node --check` on `assets/js/**/*.js`). + + ## [2.2.2] - 2026-04-29 — Front page layout restructure ### Changed diff --git a/composer.json b/composer.json index 3fedc08..d679a2b 100644 --- a/composer.json +++ b/composer.json @@ -13,7 +13,7 @@ "scripts": { "lint": "phpcs", "lint:fix": "phpcbf", - "test": "phpunit" + "test": "vendor/bin/phpunit" }, "config": { "allow-plugins": { diff --git a/functions.php b/functions.php index a1d9815..501d199 100644 --- a/functions.php +++ b/functions.php @@ -7,6 +7,8 @@ * 300 lines and to make responsibilities discoverable. * * @see inc/config.php — security configuration + * @see inc/nav-walker.php — Peptide_Starter_Nav_Walker + primary menu fallback + * @see inc/helpers.php — customizer helpers, gates, honeypot, CSV utility * @see inc/rate-limiter.php — transient-backed rate limiter * @see inc/email-verification.php — token-gated email verification * @see inc/auth-handlers.php — AJAX login + registration @@ -14,7 +16,6 @@ * @see inc/newsletter-admin.php — admin subscriber viewer + unsubscribe * @see inc/page-setup.php — auto-create pages + v1.5.0 user migration * @see inc/mail-diagnostic.php — admin deliverability test tool - * @see inc/helpers.php — nav walker, menu fallback, gates, utilities * @see inc/perf-asset-policy.php — asset dequeue + font slim + preconnect + defer * * @package peptide-starter @@ -26,13 +27,14 @@ if ( ! defined( 'ABSPATH' ) ) { } // Theme constants. -define( 'PEPTIDE_STARTER_VERSION', '2.2.2' ); +define( 'PEPTIDE_STARTER_VERSION', '2.3.0' ); define( 'PEPTIDE_STARTER_DIR', get_template_directory() ); define( 'PEPTIDE_STARTER_URI', get_template_directory_uri() ); // Load feature modules. Order matters — config must load before anything // that calls peptide_starter_config_*; rate limiter before handlers. require_once PEPTIDE_STARTER_DIR . '/inc/config.php'; +require_once PEPTIDE_STARTER_DIR . '/inc/nav-walker.php'; require_once PEPTIDE_STARTER_DIR . '/inc/helpers.php'; require_once PEPTIDE_STARTER_DIR . '/inc/cloudflare-ips.php'; require_once PEPTIDE_STARTER_DIR . '/inc/rate-limiter.php'; diff --git a/inc/helpers.php b/inc/helpers.php index 84399cf..4ac4dd8 100644 --- a/inc/helpers.php +++ b/inc/helpers.php @@ -2,17 +2,21 @@ /** * Theme Helper Functions * - * Customizer output helpers, nav walker, custom logo, pagination, menu - * fallback, auth gates, and assorted utilities shared across the theme. + * Customizer output helpers, custom logo, pagination, auth gates, + * honeypot, and CSV utility shared across the theme. * - * @see functions.php — includes this file - * @see header.php — uses peptide_starter_the_custom_logo() + menu fallback + * Navigation walker and primary menu fallback have been extracted to + * inc/nav-walker.php (v2.3.0) to keep this file under 300 lines. + * + * @see functions.php — includes this file (after nav-walker.php) + * @see inc/nav-walker.php — Peptide_Starter_Nav_Walker + menu fallback + * @see header.php — uses peptide_starter_the_custom_logo() * @see page-subject-log.php, page-tracker.php, page-protocol-builder.php — * use peptide_starter_require_login() * * What: Utility functions for template output, theme mods, auth gating. * Who calls it: Templates and handler files. - * Dependencies: WordPress Customizer API, Walker_Nav_Menu, email-verification. + * Dependencies: WordPress Customizer API, email-verification. * * @package peptide-starter */ @@ -22,110 +26,6 @@ if ( ! defined( 'ABSPATH' ) ) { exit; } -/** - * Navigation Menu Walker — adds active classes. - * - * What: Renders menu items with an 'active' class for current + ancestor. - * Who calls it: wp_nav_menu() in header.php with walker => new instance. - * Dependencies: Walker_Nav_Menu. - */ -class Peptide_Starter_Nav_Walker extends Walker_Nav_Menu { - - /** - * Render a single menu item. - * - * @param string $output Item output accumulator. - * @param WP_Post $item Menu item data. - * @param int $depth Menu depth. - * @param stdClass $args Menu arguments. - * @param int $id Current item ID. - * @return void - */ - public function start_el( &$output, $item, $depth = 0, $args = null, $id = 0 ) { - $indent = ( $depth ) ? str_repeat( "\t", $depth ) : ''; - $classes = empty( $item->classes ) ? array() : (array) $item->classes; - $classes[] = 'menu-item-' . $item->ID; - - if ( in_array( 'current-menu-item', $classes, true ) || in_array( 'current-menu-parent', $classes, true ) ) { - $classes[] = 'active'; - } - - $args = apply_filters( 'nav_menu_item_args', $args, $item, $depth ); - $class_names = join( ' ', apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item, $args, $depth ) ); - $class_names = $class_names ? ' class="' . esc_attr( $class_names ) . '"' : ''; - - $item_id = apply_filters( 'nav_menu_item_id', 'menu-item-' . $item->ID, $item, $args, $depth ); - $item_id = $item_id ? ' id="' . esc_attr( $item_id ) . '"' : ''; - - $output .= $indent . '