From c36c7d196ed662d127da160c3716d2dccca2e402 Mon Sep 17 00:00:00 2001 From: "K. Adam White" Date: Thu, 1 Oct 2026 13:53:10 -0400 Subject: [PATCH 1/9] Add PHPCS to project and introduce "composer phpcs" script --- composer.json | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/composer.json b/composer.json index b59901c..229b32a 100644 --- a/composer.json +++ b/composer.json @@ -7,6 +7,17 @@ "require": { "php": ">=7.4" }, + "require-dev": { + "humanmade/coding-standards": "^2.5" + }, + "scripts": { + "phpcs": "phpcs" + }, + "config": { + "allow-plugins": { + "dealerdirect/phpcodesniffer-composer-installer": true + } + }, "autoload": { "psr-4": { "HumanMade\\MegaMenuBlock\\": "src/" From f59c194034ba69de3a9a7a003567981c26afe9a6 Mon Sep 17 00:00:00 2001 From: "K. Adam White" Date: Thu, 1 Oct 2026 13:54:13 -0400 Subject: [PATCH 2/9] Scan code with HM-Minimum, and configure minimum recommended PHP version as 8.2 Code remains 7.4-compatible, but older PHP is out of support and the PHPCS tooling can only run on 8.2 or later. --- composer.json | 2 +- phpcs.xml.dist | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 phpcs.xml.dist diff --git a/composer.json b/composer.json index 229b32a..e509433 100644 --- a/composer.json +++ b/composer.json @@ -5,7 +5,7 @@ "license": "GPL-2.0-or-later", "require": { - "php": ">=7.4" + "php": ">=8.2" }, "require-dev": { "humanmade/coding-standards": "^2.5" diff --git a/phpcs.xml.dist b/phpcs.xml.dist new file mode 100644 index 0000000..ba26449 --- /dev/null +++ b/phpcs.xml.dist @@ -0,0 +1,24 @@ + + + Human Made coding standards for Mega Menu Block plugin. + + + . + + + */node_modules/* + */vendor/* + */build/* + + + + + + + + + + + + + From 325b3fe2ec51a2791ee82ad3f1bc6ed8fa907a41 Mon Sep 17 00:00:00 2001 From: "K. Adam White" Date: Thu, 1 Oct 2026 13:54:56 -0400 Subject: [PATCH 3/9] Add "npm run lint:php" alias for running PHPCS --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index a918654..a5926c3 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "format": "wp-scripts format", "lint:css": "wp-scripts lint-style", "lint:js": "wp-scripts lint-js", + "lint:php": "composer phpcs", "test": "wp-scripts test-unit-js", "packages-update": "wp-scripts packages-update", "plugin-zip": "wp-scripts plugin-zip", From cbdfc2199036f5821d64f1074ce444588086eb73 Mon Sep 17 00:00:00 2001 From: "K. Adam White" Date: Thu, 1 Oct 2026 13:55:47 -0400 Subject: [PATCH 4/9] CI: Add workflow to run PHPCS security checks on pull requests --- .github/workflows/phpcs.yml | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 .github/workflows/phpcs.yml diff --git a/.github/workflows/phpcs.yml b/.github/workflows/phpcs.yml new file mode 100644 index 0000000..e605e6f --- /dev/null +++ b/.github/workflows/phpcs.yml @@ -0,0 +1,29 @@ +name: PHPCS + +on: + pull_request: + paths: + - '**.php' + - 'composer.json' + - 'phpcs.xml.dist' + - '.github/workflows/phpcs.yml' + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + phpcs: + name: "Lint PHP" + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + + - uses: shivammathur/setup-php@f3e473d116dcccaddc5834248c87452386958240 # 2.37.2 + with: + php-version: '8.2' + tools: composer, cs2pr + + - run: composer install --no-progress --prefer-dist + + - run: composer phpcs -- -q --report=checkstyle | cs2pr From 54ab9416af352515df677c414fea9dfedc42bd2d Mon Sep 17 00:00:00 2001 From: "K. Adam White" Date: Thu, 1 Oct 2026 14:02:18 -0400 Subject: [PATCH 5/9] CI: Check against PHP 8.2, 8.3, and 8.4 --- .github/workflows/phpcs.yml | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/.github/workflows/phpcs.yml b/.github/workflows/phpcs.yml index e605e6f..44779ef 100644 --- a/.github/workflows/phpcs.yml +++ b/.github/workflows/phpcs.yml @@ -14,16 +14,25 @@ concurrency: jobs: phpcs: - name: "Lint PHP" + name: "Lint PHP ${{ matrix.php }}" runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + php: [ '8.2', '8.3', '8.4' ] steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - uses: shivammathur/setup-php@f3e473d116dcccaddc5834248c87452386958240 # 2.37.2 with: - php-version: '8.2' + php-version: ${{ matrix.php }} tools: composer, cs2pr - run: composer install --no-progress --prefer-dist - - run: composer phpcs -- -q --report=checkstyle | cs2pr + # Only the first (lowest) version annotates the PR, to avoid duplicate comments. + - if: strategy.job-index == 0 + run: composer phpcs -- -q --report=checkstyle | cs2pr + + - if: strategy.job-index != 0 + run: composer phpcs -- --no-colors From b0189d6bc5203ececa788f451c2cbe43f16939e5 Mon Sep 17 00:00:00 2001 From: "K. Adam White" Date: Thu, 1 Oct 2026 14:21:08 -0400 Subject: [PATCH 6/9] Add wp-env local test environment and "npm run env:*" commands --- .wp-env.json | 15 +++++++++++++++ README.md | 17 +++++++++++++++++ package.json | 6 ++++++ 3 files changed, 38 insertions(+) create mode 100644 .wp-env.json diff --git a/.wp-env.json b/.wp-env.json new file mode 100644 index 0000000..8d1c700 --- /dev/null +++ b/.wp-env.json @@ -0,0 +1,15 @@ +{ + "port": 6368, + "phpVersion": "8.2", + "testsEnvironment": false, + "config": { + "SCRIPT_DEBUG": true, + "WP_DEBUG_DISPLAY": false, + "WP_DEBUG": true, + "WP_DEVELOPMENT_MODE": "plugin" + }, + "plugins": [ + ".", + "https://downloads.wordpress.org/plugin/query-monitor.zip" + ] +} diff --git a/README.md b/README.md index 88effcc..9dba3d4 100644 --- a/README.md +++ b/README.md @@ -71,6 +71,23 @@ This guide explains how to create and customize a mega menu using the HM Mega Me This plugin provides a flexible, code-light way to build and customize mega menus in WordPress! +## Local Environment + +This project uses [wp-env](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-env/) to run a lightweight, containerized WordPress instance at [localhost:6368](http://localhost:6368) for testing purposes. The default username for the localhost environment is `admin`, with the password `password`. Run `npm run build` (or `npm start`) first so the block assets exist. + +These commands can be used to interact with the environment: + +Command | Purpose +---- | ---- +`npm run env:start` | Start the local environment at http://localhost:6368 +`npm run env:stop` | Turn off the local environment +`npm run env:cli -- wp ...` | Run WP-CLI commands within the environment +`npm run env:logs` | Open (and tail) the error logs for the application‡ +`npm run env:db` | Open the database in the mysql command line +`npm run env:destroy` | Fully destroy the local environment (deletes container database) + +‡ This command deliberately filters out GET/OPTIONS/HEAD/POST/PUT access log entries + ## Release Process Merges to `main` will automatically build to the `release` branch. diff --git a/package.json b/package.json index a5926c3..0ae3567 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,12 @@ "main": "build/index.js", "scripts": { "build": "wp-scripts build --experimental-modules", + "env:cli": "npx @wordpress/env run cli", + "env:db": "npx @wordpress/env run cli -- mysql -uroot -ppassword wordpress --host=mysql", + "env:destroy": "npx @wordpress/env destroy", + "env:logs": "npx @wordpress/env logs development | grep -v -E '\"(GET|OPTIONS|HEAD|POST|PUT)'", + "env:start": "npx @wordpress/env start", + "env:stop": "npx @wordpress/env stop", "format": "wp-scripts format", "lint:css": "wp-scripts lint-style", "lint:js": "wp-scripts lint-js", From 9569b219a2efb19f0e8293a8876d905ebe111d19 Mon Sep 17 00:00:00 2001 From: "K. Adam White" Date: Thu, 1 Oct 2026 14:32:26 -0400 Subject: [PATCH 7/9] Add local environment test data setup command to aid in testing --- README.md | 1 + bin/bootstrap-env.php | 151 ++++++++++++++++++++++++++++++++++++++++++ package.json | 1 + 3 files changed, 153 insertions(+) create mode 100644 bin/bootstrap-env.php diff --git a/README.md b/README.md index 9dba3d4..ee32c40 100644 --- a/README.md +++ b/README.md @@ -80,6 +80,7 @@ These commands can be used to interact with the environment: Command | Purpose ---- | ---- `npm run env:start` | Start the local environment at http://localhost:6368 +`npm run env:bootstrap` | Seed demo "Products" and "Resources" mega menus into the Twenty Twenty-Five header (safe to re-run) `npm run env:stop` | Turn off the local environment `npm run env:cli -- wp ...` | Run WP-CLI commands within the environment `npm run env:logs` | Open (and tail) the error logs for the application‡ diff --git a/bin/bootstrap-env.php b/bin/bootstrap-env.php new file mode 100644 index 0000000..373769a --- /dev/null +++ b/bin/bootstrap-env.php @@ -0,0 +1,151 @@ + $postarr['post_type'], + 'name' => $postarr['post_name'], + 'post_status' => 'any', + 'posts_per_page' => 1, + 'fields' => 'ids', + ] ); + + if ( $existing ) { + $postarr['ID'] = $existing[0]; + } + + $post_id = wp_insert_post( wp_slash( $postarr + [ 'post_status' => 'publish' ] ), true ); + + if ( is_wp_error( $post_id ) ) { + WP_CLI::error( $post_id ); + } + + return $post_id; +} + +/** + * Build demo template part content: one column of links per heading. + * + * @param array $columns Map of column heading => list of link labels. + * @return string Block markup. + */ +function hm_mega_menu_bootstrap_menu_content( array $columns ) : string { + $markup = ''; + + foreach ( $columns as $heading => $links ) { + $items = ''; + foreach ( $links as $link ) { + $items .= sprintf( '
  • %s
  • ', esc_html( $link ) ); + } + + $markup .= sprintf( + '

    %s

      %s
    ', + esc_html( $heading ), + $items + ); + } + + return '
    ' + . $markup + . '
    '; +} + +$theme = get_stylesheet(); + +$menus = [ + 'mega-menu-products' => [ + 'title' => 'Mega Menu: Products', + 'block' => [ + 'label' => 'Products', + 'width' => 'wide', + ], + 'columns' => [ + 'Hardware' => [ 'Laptops', 'Phones', 'Accessories' ], + 'Software' => [ 'Editor', 'Hosting', 'Analytics' ], + 'Services' => [ 'Support', 'Training' ], + ], + ], + 'mega-menu-resources' => [ + 'title' => 'Mega Menu: Resources', + 'block' => [ + 'label' => 'Resources', + 'labelColor' => '#c0392b', + 'width' => 'content', + 'justifyMenu' => 'right', + ], + 'columns' => [ + 'Learn' => [ 'Documentation', 'Tutorials' ], + 'Community' => [ 'Forums', 'Events' ], + ], + ], +]; + +$nav_items = ''; + +foreach ( $menus as $slug => $menu ) { + $part_id = hm_mega_menu_bootstrap_upsert_post( [ + 'post_type' => 'wp_template_part', + 'post_name' => $slug, + 'post_title' => $menu['title'], + 'post_content' => hm_mega_menu_bootstrap_menu_content( $menu['columns'] ), + ] ); + wp_set_object_terms( $part_id, $theme, 'wp_theme' ); + wp_set_object_terms( $part_id, 'menu', 'wp_template_part_area' ); + + $nav_items .= sprintf( + '', + wp_json_encode( $menu['block'] + [ 'menuSlug' => $slug ] ) + ); + + WP_CLI::log( sprintf( 'Template part "%s": %d', $slug, $part_id ) ); +} + +$nav_items .= ''; + +$nav_id = hm_mega_menu_bootstrap_upsert_post( [ + 'post_type' => 'wp_navigation', + 'post_name' => 'mega-menu-demo', + 'post_title' => 'Mega Menu Demo', + 'post_content' => $nav_items, +] ); +WP_CLI::log( sprintf( 'Navigation "mega-menu-demo": %d', $nav_id ) ); + +// Override the theme header, pointing its Navigation block at the demo menu. +$header = WP_Block_Patterns_Registry::get_instance()->get_registered( $theme . '/header' ); +if ( ! $header ) { + WP_CLI::error( sprintf( 'No "%s/header" pattern found; the bootstrap targets Twenty Twenty-Five.', $theme ) ); +} + +$header_content = preg_replace( '/