Skip to content

fix[faustwp]: (#1872) use home_url() in handle_generate_endpoint#2339

Merged
josephfusco merged 5 commits into
wpengine:canaryfrom
latenighthackathon:fix/faustwp-search-pattern-home-url
May 13, 2026
Merged

fix[faustwp]: (#1872) use home_url() in handle_generate_endpoint#2339
josephfusco merged 5 commits into
wpengine:canaryfrom
latenighthackathon:fix/faustwp-search-pattern-home-url

Conversation

@latenighthackathon
Copy link
Copy Markdown
Contributor

@latenighthackathon latenighthackathon commented Apr 21, 2026

Summary

On Bedrock-style installs where WordPress core lives under /wp/, site_url('/generate', 'relative') returns /wp/generate but $_SERVER['REQUEST_URI'] is still /generate. The preg_match in handle_generate_endpoint() never fires and the auth-code redirect silently breaks.

home_url() returns the public-facing URL — which is what REQUEST_URI actually contains. Same value as site_url() for standard installs (no observable change there), and the correct value for Bedrock + other split-install layouts (WP_HOMEWP_SITEURL).

Related Issue

Closes #1872

Refiled per @josephfusco's guidance on closed PR #2315 — a new filter is not needed, just the correct URL helper.

Confirm the issue (on canary)

grep -n "site_url.*/generate" plugins/faustwp/includes/auth/callbacks.php
# Expected: 25: $search_pattern = ':^' . site_url( '/generate', 'relative' ) . ':';

Confirm the fix (this branch)

grep -n "home_url.*/generate" plugins/faustwp/includes/auth/callbacks.php
# Expected: 25: $search_pattern = ':^' . home_url( '/generate', 'relative' ) . ':';

Run the test suite (corrected from earlier draft)

NOTE: there is no package.json in plugins/faustwp/. The plugin's scripts are Composer scripts, not npm scripts. The commands below are what CI runs (.github/workflows/unit-test-plugin.yml).

cd plugins/faustwp
composer install

# Static checks
composer phpcs

# Bring up the test stack (PHP 8.2 + WP 6.8 by default; override with WP_VERSION=6.9 etc.)
WP_VERSION=6.8 composer run docker:start
docker compose exec wordpress init-testing-environment.sh
docker compose exec -w /var/www/html/wp-content/plugins/faustwp wordpress \
  wp plugin install wp-graphql --activate --allow-root

# Run the new AuthCallbacks suite (single-site)
docker compose exec -w /var/www/html/wp-content/plugins/faustwp wordpress \
  ./vendor/bin/phpunit --filter=AuthCallbacks
# Expected: OK (4 tests, 5 assertions)

The new test file is plugins/faustwp/tests/integration/AuthCallbacksTests.php. It includes a set_bedrock_layout() helper that filters site_url to inject /wp/ (both relative and absolute URL forms) so the divergence is reproducible without a real Bedrock install. The test_bedrock_divergence_matches_with_home_url case is the regression guard — verified to fail when callbacks.php is reverted to site_url(), pass with the fix in place.

Manual Bedrock reproduction

A small mu-plugin lives at plugins/faustwp/tests/mu-plugins/mu-bedrock-simulator.php. Drop it into the running container's mu-plugins/ to make site_url() return /wp/<path> while home_url() stays at /<path>:

docker compose -f plugins/faustwp/docker-compose.yml exec wordpress sh -c \
  'mkdir -p /var/www/html/wp-content/mu-plugins \
   && cp /var/www/html/wp-content/plugins/faustwp/tests/mu-plugins/mu-bedrock-simulator.php /var/www/html/wp-content/mu-plugins/'

Verify the divergence:

docker compose -f plugins/faustwp/docker-compose.yml exec -w /var/www/html wordpress \
  wp eval 'echo "site_url: " . site_url("/generate", "relative") . PHP_EOL; echo "home_url: " . home_url("/generate", "relative") . PHP_EOL;' --allow-root
# Expected:
#   site_url: http://localhost:8080/wp/generate
#   home_url: http://localhost:8080/generate

Then visit http://localhost:8080/generate?redirect_uri=https://example.test/ — handler matches and redirects to wp-login.php.

Checklist

  • Targets canary
  • Changeset added (@faustwp/wordpress-plugin patch)
  • Regression test added (tests/integration/AuthCallbacksTests.php) — 4 cases incl. Bedrock divergence guard
  • Bedrock simulator added (tests/mu-plugins/mu-bedrock-simulator.php) for manual repro
  • PHPCS clean on touched files
  • PHPUnit green on single-site and multisite (./vendor/bin/phpunit -c ./phpunit-multisite.xml.dist --filter=AuthCallbacks)

On Bedrock-style installs where WordPress core lives under /wp/,
site_url('/generate') returns https://example.com/wp/generate but
$_SERVER['REQUEST_URI'] is still /generate, so the preg_match in
handle_generate_endpoint() never fires and the auth-code redirect
silently breaks.

home_url() returns the public-facing URL (what REQUEST_URI actually
contains), which matches on both standard and Bedrock installs.

Per @josephfusco's guidance on wpengine#2315, which was closed in favor of
this simpler fix — a new filter is not needed, just the correct URL
helper.
@latenighthackathon latenighthackathon requested a review from a team as a code owner April 21, 2026 03:29
@headless-platform-by-wp-engine
Copy link
Copy Markdown

Currently, we do not support the creation of preview deployments based on changes coming from forked repositories.
Learn more about preview environments in our documentation.

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Apr 21, 2026

🦋 Changeset detected

Latest commit: 4d19bbd

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@faustwp/wordpress-plugin Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

… case (wpengine#1872)

Adds AuthCallbacksTests.php covering handle_generate_endpoint() with four
scenarios:

- Standard install reaches wp_safe_redirect (login redirect path).
- Bedrock layout (site_url=/wp/x, home_url=/x) still matches REQUEST_URI=/x.
  This is the regression guard against future reverts to site_url(): verified
  to fail when callbacks.php is reverted to site_url() and pass with home_url().
- Unrelated REQUEST_URI early-returns without redirecting.
- /generate without redirect_uri early-returns.

Uses Patchwork to redefine wp_safe_redirect so the bare 'exit;' is bypassed
and the captured redirect target can be asserted. Patchwork is already loaded
via phpunit.xml.dist's LOAD_PATCHWORK=1.

Also adds tests/mu-plugins/mu-bedrock-simulator.php -- a tiny mu-plugin that
makes site_url() return /wp/<path> while home_url() stays at /<path>, for
manual browser reproduction inside the docker-compose stack without requiring
a full roots/bedrock install.
Peer-review polish on the earlier test commit:

- Use update_option('siteurl', ...) instead of an add_filter('site_url')
  to drive Bedrock-style URL divergence. This matches what real Bedrock
  configures via WP_SITEURL in wp-config.php, so every consumer of
  get_option('siteurl') and site_url() sees the divergent value, not just
  callers that go through the site_url filter. Removes the remove_all_filters()
  tearDown that nuked unrelated core filters.

- Replace the RuntimeException + magic-string catch trick with a dedicated
  RedirectAttempted exception class. Eliminates the risk of accidentally
  swallowing unrelated runtime errors during the redirect-capture flow.

- Tighten assertions on the Bedrock-divergence test: now also asserts the
  captured redirect contains 'wp-login.php' (matching the standard-install
  test) and adds two sanity-check assertions that confirm the simulated
  divergence is actually in place before the handler is invoked. Total
  assertions in the suite increase from 5 to 8.

- Document the simulator mu-plugin's narrower scope vs the test's full
  fidelity: the mu-plugin filters site_url() output (sufficient for browser
  reproduction), while the PHPUnit suite updates the option directly.

Verified via temporary revert of callbacks.php to site_url(): the Bedrock
divergence test now fails with the polished message; restoring home_url()
greens the suite on both single-site and multisite.
…ilter caveat

Three small additions on top of the regression-test commits:

1. Assert that the redirect_uri query arg is preserved through to the
   wp-login redirect_to param, in both the standard and Bedrock cases.
   A future change that successfully matched the request but mangled or
   dropped redirect_uri would previously slip through.

2. Add test_wp_in_subdirectory_install_matches_with_home_url for the
   Codex-documented 'Giving WordPress its own directory' pattern -- WP
   core in /wordpress, public site at root. Different prefix from Bedrock,
   same shape of divergence. Proves the fix is not a /wp-special case.
   Renames set_bedrock_siteurl() to set_split_install_siteurl($suffix)
   so both tests share the helper.

3. Document the home_url() filter dependency in handle_generate_endpoint()'s
   docblock. Multilingual plugins (WPML, Polylang, TranslatePress) that
   filter home_url() to prepend locale paths can still cause this match to
   miss for non-locale-prefixed frontend callers. Notes the likely follow-up
   direction (REST route migration) so the next person to touch this knows
   what they're inheriting.

Suite is now 5 tests / 14 assertions. Verified red-on-revert: both the
Bedrock and WP-in-subdirectory tests fail cleanly when callbacks.php is
reverted to site_url(); restoring home_url() greens both single-site and
multisite suites.
@josephfusco josephfusco enabled auto-merge (squash) May 13, 2026 14:29
…est classes

phpunit.xml.dist sets backupGlobals="false", so anything mutated on
$_SERVER and $_GET inside one test class persists to the next. Our
tearDown was doing 'unset($_SERVER[REQUEST_URI])' as cleanup, which
poisoned the cron path that runs during TelemetryCallbacksTests::setUp()
(do_action('muplugins_loaded') -> wp-cron -> reads REQUEST_URI). With
convertNoticesToExceptions=true, the missing key turned into 9 hard
errors on the next test class.

Local --filter=AuthCallbacks didn't surface this because TelemetryCallbacks
was excluded. CI runs the full suite and caught it on WP 6.5 and Nightly.

Fix: snapshot $_SERVER['REQUEST_URI'] and $_GET in setUp; restore them in
tearDown. The world is left as we found it, regardless of what the WP test
bootstrap or earlier test classes had configured.

Verified locally:
- Full suite (composer test, single-site + multisite): 126 tests, 291
  assertions, all pass.
- Regression guard preserved: reverting callbacks.php to site_url() still
  fails the Bedrock + WP-in-subdirectory tests cleanly.
- Without this fix, the same full suite errors 9 times in
  TelemetryCallbacksTests with 'Undefined array key REQUEST_URI' --
  matching the CI failure exactly.
@josephfusco josephfusco merged commit b6eebd5 into wpengine:canary May 13, 2026
16 checks passed
@headless-platform-by-wp-engine
Copy link
Copy Markdown

Currently, we do not support the creation of preview deployments based on changes coming from forked repositories.
Learn more about preview environments in our documentation.

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.

Add filter for search_pattern in handle_generate_endpoint

2 participants