Skip to content

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

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

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

Conversation

@dd32
Copy link
Copy Markdown
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
Copy Markdown

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
Copy Markdown
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; Resolved in 7822382

dd32 and others added 10 commits March 12, 2026 16:13
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add ?context=raw to the plugin info endpoint, returning raw post data,
public meta, and taxonomy terms without transformations.

Rewrite import-plugins.php to use it, eliminating asset URL conversion,
rating scaling, FAQ HTML munging, and section parsing.

Also fix undefined array key warnings in ratings schema and
create_plugin_post().

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Properties must be associative arrays with type definitions, not flat
string arrays. Same fix as class-ratings.php in the previous commit.

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

Move all register_meta() and register_rest_field() calls into a single
api/class-plugin-fields.php, replacing the five individual field classes.
Fix meta schemas to match actual stored data formats (sections as array,
tags as object with nested metadata, assets_screenshots as keyed object,
screenshots as caption strings). Add show_in_rest to plugin_section,
plugin_tags, plugin_contributors, and plugin_business_model taxonomies.
Enhance plugin_contributors terms with display_name, avatar, and profile
fields. Remove the custom ?context=raw endpoint in favor of standard
/wp/v2/plugin with _embed. Update import script accordingly.

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

The plugin post type registers with supports=['comments','author','custom-fields','media']
(no 'title'), so the REST API returns title:null. Fall back to meta.header_name instead.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Increase per-section import count from 10 to 15
- Add 'new' and 'updated' browse sections for variety
- Show plugin slug during import and name on completion
- Show friendly names for page and section term creation in after-start

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Set post_modified from last_updated meta so "Recently Updated" works
- Use wp_insert_post_data filter to preserve dates through wp_update_post
- Store _active_installs (underscore-prefixed) for sorting queries
- Capitalize section term names (Featured, Popular, etc.)
- Add blocks browse section for block-enabled plugins

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
bazza pushed a commit that referenced this pull request Mar 13, 2026
…a on the plugin post type.

This allows for local development environment to import plugins without parsing APIs that generate content from it.
This results in a more complete import, and less parsing issues.

See #555 


git-svn-id: https://meta.svn.wordpress.org/sites/trunk@14705 74240141-8908-4e6f-9713-ba540dce6ec7
…-directory-wp-env

# Conflicts:
#	wordpress.org/public_html/wp-content/plugins/plugin-directory/api/class-plugin-fields.php
#	wordpress.org/public_html/wp-content/plugins/plugin-directory/class-plugin-directory.php
bazza pushed a commit that referenced this pull request Mar 13, 2026
This was missed in [14705].
See #555


git-svn-id: https://meta.svn.wordpress.org/sites/trunk@14706 74240141-8908-4e6f-9713-ba540dce6ec7
dd32 and others added 13 commits March 13, 2026 16:37
Forks syncing trunk were triggering CI runs unnecessarily. The `if`
condition ensures push events only run on the upstream repository while
pull_request events run everywhere.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fetch plugin data in batches of 10 using slug[] parameter instead of
one HTTP request per plugin. Reduces ~90 requests down to ~12 total.
Increased wp_remote_get timeout to 60s for larger batch responses.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Suppress WP-CLI stdout from post/term creation so only custom echo
messages show. Simplify slug fetching to a single API request with
posts_per_page. Track imported slugs across sections so duplicates
are tagged rather than re-imported.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…v and trim README.

Moves wporg-plugins-local-reminders.php from the shared mocks directory
into environments/plugin-directory/ since it is specific to that
environment. Also removes the "What it includes" section from README.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…fig.

wp-env resolves relative paths from the working directory, not the
config file location. Updated the path accordingly.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
bazza pushed a commit that referenced this pull request Mar 16, 2026
… directory.

This also provides an environment in which we can run integration & unit tests in.

Merges #555


git-svn-id: https://meta.svn.wordpress.org/sites/trunk@14720 74240141-8908-4e6f-9713-ba540dce6ec7
@dd32
Copy link
Copy Markdown
Member Author

dd32 commented Mar 16, 2026

Merged in bc3041f

@dd32 dd32 closed this Mar 16, 2026
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