Skip to content

Plugin Directory: Add wp-env local development environment#555

Open
dd32 wants to merge 56 commits intoWordPress:trunkfrom
dd32:create/claude/plugin-directory-wp-env
Open

Plugin Directory: Add wp-env local development environment#555
dd32 wants to merge 56 commits intoWordPress:trunkfrom
dd32:create/claude/plugin-directory-wp-env

Conversation

@dd32
Copy link
Member

@dd32 dd32 commented Feb 23, 2026

Summary

Local development environment for the Plugin Directory using wp-env (Docker, PHP 8.4).

Environment setup:

cd environments && npm install
npm run plugins:env start

On first start, ~30 plugins are auto-imported from wordpress.org (featured, popular, beta sections).

What works

  • Plugin browsing, single plugin pages, and search
  • Plugin submissions and the review/approval process
  • Readme validator, block plugin checker, release management pages
  • Dev login button on wp-login for quick admin access
  • npm run plugins:import <slug> to import individual plugins from SVN
  • npm run plugins:refresh to re-import all plugin metadata from the API
  • Admin notice reminding to import approved plugins via CLI

What does not work

  • Trigger SVN Sync button
  • Custom crons tightly coupled to Cavalcade
  • Commits metabox (no trac_plugins table)
  • HelpScout metabox (no HelpScout access)
  • Reviews (could be mocked in future)

Changes

Environment (environments/)

  • plugin-directory/.wp-env.json — wp-env config with PHP 8.4, mu-plugin mocks, theme mappings, lifecycle scripts
  • plugin-directory/bin/after-start.sh — Installs CLI tools (svn, unzip, zip), sets up permalinks, creates pages, imports stub DB tables, creates browse terms, imports plugins
  • plugin-directory/bin/import-plugins.php — Bulk imports plugin data from the wordpress.org REST API (metadata, users, icons, banners, screenshots, tags, contributors, committer access)
  • plugin-directory/bin/database-tables.sql — Stub wp_svn_access and wp_update_source tables
  • mocks/mu-plugins-loader.php — Loads mu-plugins from pub/ and wporg-mu-plugins/
  • mocks/wporg-query-filter.php — Intercepts queries to production-only tables
  • mocks/wporg-dev-login.php — One-click admin login on wp-login screen
  • mocks/wporg-plugins-local-reminders.php — Admin notice for approved plugins needing import
  • .nvmrc — Node 20 requirement

Plugin Directory code fixes

  • Gate SVN credential usage on defined() checks, bail on writes without credentials
  • Fix SVN::ls() fatal when XML parsing fails (no SVN server)
  • Fix undefined $plugins_prefix variable in custom_redirect()
  • Fix /readme.txt redirect path for non-/plugins/ environments
  • Gate HelpScout stats on HELPSCOUT_PLUGINS_MAILBOXID constant
  • Gate Two_Factor and is_email_address_unsafe() on existence checks

CI / Testing

  • Flatten test directory structure (tests/phpunit/tests/ to tests/)
  • Update bootstrap for wp-env test framework compatibility
  • Add Plugin Directory to GitHub Actions using environments wp-env with cli container
  • Remote API tests excluded from CI suite

Test plan

  • cd environments && npm install && npm run plugins:env start
  • Verify plugins are imported with icons, banners, and contributors
  • Browse featured/popular/beta sections
  • View a single plugin page without errors
  • Submit a new plugin via /developers/add/
  • Approve a plugin and verify the import notice appears
  • Run npm run plugins:import <slug> for an approved plugin
  • Run npm run plugins:refresh to re-import metadata
  • Verify CI passes

🤖 Generated with Claude Code

@dd32 dd32 force-pushed the create/claude/plugin-directory-wp-env branch 2 times, most recently from 1b81fe3 to efc2a91 Compare February 23, 2026 08:28
bazza pushed a commit that referenced this pull request Mar 10, 2026
bazza pushed a commit that referenced this pull request Mar 10, 2026
bazza pushed a commit that referenced this pull request Mar 10, 2026
bazza pushed a commit that referenced this pull request Mar 10, 2026
…heck get_site() exists.

See #555


git-svn-id: https://meta.svn.wordpress.org/sites/trunk@14686 74240141-8908-4e6f-9713-ba540dce6ec7
bazza pushed a commit that referenced this pull request Mar 10, 2026
We've been using teh bundled Jetpack Search for long enough now.

This helps with local environments.

See #555


git-svn-id: https://meta.svn.wordpress.org/sites/trunk@14687 74240141-8908-4e6f-9713-ba540dce6ec7
@dd32 dd32 marked this pull request as ready for review March 10, 2026 03:52
bazza pushed a commit that referenced this pull request Mar 10, 2026
…voids deprecation warnings.

See #555


git-svn-id: https://meta.svn.wordpress.org/sites/trunk@14688 74240141-8908-4e6f-9713-ba540dce6ec7
@github-actions
Copy link

github-actions bot commented Mar 10, 2026

The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the props-bot label.

Core Committers: Use this line as a base for the props when committing in SVN:

Props dd32, obenland.

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

@dd32 dd32 closed this Mar 10, 2026
@dd32 dd32 reopened this Mar 10, 2026
dd32 and others added 3 commits March 10, 2026 15:15
Adds a wp-env configuration for running the plugin directory locally,
with mocks for production-only services and a lifecycle script that
seeds plugin data from the WordPress.org API after first start.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ments.

- Gate Jetpack Search class instantiation behind class_exists checks
- Only rewrite asset URLs to CDN when wp_get_environment_type() is production
- Fix get_site() fatal on non-multisite in locale banner route
- Fix PHP 8.2 dynamic property deprecation on WP_List_Table subclass
- Fix false-to-array deprecation in get_plugin_banner() fallback
- Fix undefined HTTP_HOST/REQUEST_URI warnings in CLI context

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…entation.

- Update PHP version from 8.1 to 8.4
- Remove wporg-ratings mock (code has class_exists guards)
- Add npm script for starting the environment
- Add README documenting available environments

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@dd32 dd32 force-pushed the create/claude/plugin-directory-wp-env branch from a70bc3c to e24f03c Compare March 10, 2026 05:21
dd32 and others added 8 commits March 10, 2026 15:26
…d refresh command.

- Revert class-plugin-search.php old Jetpack fallback (not needed with current Jetpack)
- Rename wp-env:plugin-directory script to plugins:env
- Add plugins:refresh script to re-import plugins from WordPress.org

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add Plugin Directory to the WordPress-dependent CI matrix using wp-env.
Add .wp-env.json, enhance bootstrap.php with wp-env test framework
detection, and add comprehensive unit tests for templates, trademarks,
readme parsing, markdown, readme validation, and plugin registration.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Change plugins:env to pass-through wp-env commands (e.g. plugins:env start)
- Add plugins:import script to import a plugin by slug
- Rewrite wporg-query-filter.php to use $wpdb->get_table_from_query()
- Block all trac_* tables, not just trac_plugins

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove unit test files, workflow changes, and bootstrap modifications
that were incorrectly included from a bad merge. These belong to a
separate PR.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Map mu-plugins/pub and mu-plugins/wporg-mu-plugins as subdirectories
instead of replacing the entire mu-plugins directory. This allows
individual file mappings (loader, query-filter) to work alongside them.
Update the loader to load all PHP files from pub/ and the
wporg-mu-plugins loader.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@dd32 dd32 closed this Mar 10, 2026
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@dd32 dd32 reopened this Mar 10, 2026
dd32 and others added 3 commits March 10, 2026 16:28
- Fix relative paths: wp-env resolves from CWD, not .wp-env.json location
- Add WP_TESTS_TITLE config
- Fix query filter: wpdb::get_table_from_query() is protected, use a
  subclass with a no-op constructor to expose it

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Runs 'wp rewrite structure /%postname%/ --hard' in afterStart to
generate .htaccess since it does not exist in the container.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@dd32
Copy link
Member Author

dd32 commented Mar 12, 2026

@obenland I suggest... running a destroy, I've also updated the packages just incase that was related..

For some reason, even when using --config the mapping paths are relative to where you're running the command from, not relative to the wp-env config, which I think could be part of the problem, along with a invalid docker mount config from a previous iteration of the environment..

Claude was incorrect in the assumption behind 39d164b...

@dd32 dd32 force-pushed the create/claude/plugin-directory-wp-env branch from 6804683 to 29d2dca Compare March 12, 2026 01:44
Remove the FAQ markup conversion (API content is already processed)
and drop <!--/section--> closing tags to match the format expected
by split_post_content_into_pages().

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@dd32 dd32 force-pushed the create/claude/plugin-directory-wp-env branch from 29d2dca to b16f697 Compare March 12, 2026 01:48
dd32 and others added 2 commits March 12, 2026 11:55
Instead of skipping plugins that already exist, re-import their
content, meta, contributors, and committer access on refresh.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Both the wordpress (Debian) and cli (Alpine) containers get
subversion and unzip installed via sudo, skipping if already present.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@dd32 dd32 force-pushed the create/claude/plugin-directory-wp-env branch from 291ca7a to cd3eaf4 Compare March 12, 2026 02:07
dd32 and others added 4 commits March 12, 2026 12:13
Return false early when simplexml_load_string returns false or
the XML has no list element, instead of attempting to access
properties on a non-object. This occurs in local dev environments
where no SVN server is available.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Gate PLUGIN_SVN_MANAGEMENT_USER/PASS access on defined() so
environments without the constants (like local dev) can still
perform read operations against public SVN repos. Write operations
(import, commit, mkdir, copy/move) return early with an error
when no credentials are available.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Used by API_Update_Updater to track plugin update data.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
bazza pushed a commit that referenced this pull request Mar 12, 2026
…_exists checks to prevent fatal errors when Two_Factor plugin is not active.

  - Skip 2FA revalidation in release confirmation API when Two_Factor_Core class is unavailable
  - Wrap Two_Factor_Core::is_user_using_two_factor() calls in release confirmation shortcode
  - Guard user_requires_2fa() and is_email_address_unsafe() calls in upload shortcode

This allows for the plugin directory to be used in a local environment.

See #555


git-svn-id: https://meta.svn.wordpress.org/sites/trunk@14698 74240141-8908-4e6f-9713-ba540dce6ec7
bazza pushed a commit that referenced this pull request Mar 12, 2026
…cks.

Avoid fatal errors when PLUGIN_SVN_MANAGEMENT_USER is not defined by checking before use, and returning early with an error when no credentials are available.

Additionally, a quickfix for a potential fatal in svn ls XML parsing.

See #555


git-svn-id: https://meta.svn.wordpress.org/sites/trunk@14699 74240141-8908-4e6f-9713-ba540dce6ec7
bazza pushed a commit that referenced this pull request Mar 12, 2026
Instead of hardcoded array indices assuming a fixed URL structure, strip the home_url path prefix to get relative path segments.
This makes 404 redirects work correctly in non-production environments.

See #555


git-svn-id: https://meta.svn.wordpress.org/sites/trunk@14700 74240141-8908-4e6f-9713-ba540dce6ec7
dd32 and others added 3 commits March 12, 2026 13:33
The variable was a typo — should be $path_prefix which is defined on the line above.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…to create/claude/plugin-directory-wp-env
bazza pushed a commit that referenced this pull request Mar 12, 2026
…LPSCOUT_PLUGINS_MAILBOXID constant.

Wrap HelpScout DB queries, API calls, and the Help Scout Queue Stats display section in defined() checks
to avoid errors when the HelpScout tables and API are not available.
Also adds null-safe defaults for the in_queue_pending_why stats.

For local-development environments.

See #555


git-svn-id: https://meta.svn.wordpress.org/sites/trunk@14701 74240141-8908-4e6f-9713-ba540dce6ec7
dd32 and others added 9 commits March 12, 2026 13:56
…to create/claude/plugin-directory-wp-env
Removes custom CSS and reuses the submit button classes directly.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Also add .nvmrc for Node 20 requirement.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… wp-env

- Flatten tests/phpunit/tests/ to tests/
- Update bootstrap to find wp-env test framework at /wordpress-phpunit/
- Update phpunit.xml to exclude remote API tests
- Add Plugin Directory to CI workflow using environments wp-env with cli container

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Exclude bootstrap.php from test suite discovery
- Restore handbook explicit phpunit args for PHPUnit 10 compatibility
- Add JETPACK_DEV_DEBUG to wp-env config

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@dd32
Copy link
Member Author

dd32 commented Mar 12, 2026

At this point, I think it's as about complete as it's going to be for now.

Plugin submissions work, as does the review process.
In c87b0b2 I've added a reminder that once the plugin is approved, it needs to be imported (I'm assuming that people submit real plugins to test it...)

Some things don't work

  • Trigger SVN Sync button
  • Custom Crons that are tightly coupled to Cavalcade
  • Commits metabox (no trac_plugins table)
  • Helpscout metabox (no helpscout access)
  • No reviews (Could mock it)

It would be "helpful" if the Global WordPress Header/Footer detected running locally and semi-disabled itself, but that's outside of this issues scope.

It would also be helpful if we had an API on w.org that dumps out get_post() + array_intersect( $public_safe_fields, get_metadata() ), which would allow a faster provisioning for plugins... It would avoid the current Metadata -> API output -> API Parsing -> Local metadata

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants