Skip to content

fix[faustwp]: (#1872) add filter for search_pattern in handle_generate_endpoint#2315

Closed
latenighthackathon wants to merge 1 commit into
wpengine:canaryfrom
latenighthackathon:fix/faustwp-generate-endpoint-filter
Closed

fix[faustwp]: (#1872) add filter for search_pattern in handle_generate_endpoint#2315
latenighthackathon wants to merge 1 commit into
wpengine:canaryfrom
latenighthackathon:fix/faustwp-generate-endpoint-filter

Conversation

@latenighthackathon
Copy link
Copy Markdown
Contributor

Description

Non-standard WordPress installations like Bedrock use a different directory structure where site_url() returns a path with a /wp/ prefix (e.g. /wp/generate) but $_SERVER['REQUEST_URI'] contains only /generate. This causes the preg_match in handle_generate_endpoint() to fail, resulting in 404 errors when previewing content.

This PR adds an apply_filters() call on $search_pattern so sites with non-standard directory structures can adjust the matching pattern without modifying the plugin source.

Usage example for Bedrock:

add_filter( 'faustwp_generate_endpoint_search_pattern', function ( $pattern ) {
    return str_replace( '/wp/', '/', $pattern );
} );

Related Issues

Closes #1872

Testing

Confirm the issue (before the fix)

1. Verify no filter exists on $search_pattern:

grep -n 'apply_filters.*search_pattern' plugins/faustwp/includes/auth/callbacks.php
# Expected on canary: no output

2. Verify $search_pattern uses site_url() which includes subdirectories on Bedrock:

sed -n '25,27p' plugins/faustwp/includes/auth/callbacks.php
# Expected: $search_pattern = ':^' . site_url( '/generate', 'relative' ) . ':';
# On Bedrock, site_url() returns /wp/generate, but REQUEST_URI has /generate

Confirm the fix

3. Verify the filter is applied after $search_pattern is constructed:

grep -A 12 "search_pattern = ':^'" plugins/faustwp/includes/auth/callbacks.php | head -15
# Expected: apply_filters( 'faustwp_generate_endpoint_search_pattern', $search_pattern )
# between the assignment and the preg_match

4. Verify the docblock follows WordPress standards (@SInCE, @param):

grep -B 10 'apply_filters' plugins/faustwp/includes/auth/callbacks.php | grep '@'
# Expected: @since 1.8.7 and @param string $search_pattern

Run the test suites

phpcs — confirms the filter follows WordPress coding standards:

cd plugins/faustwp && composer install && composer phpcs

JS tests — confirms no regressions:

npm install && npm run build && npm run test

WordPress PHPUnit — confirms plugin functionality:

cd plugins/faustwp
composer run docker:start
docker-compose exec -e COVERAGE=1 wordpress init-testing-environment.sh
docker exec --workdir=/var/www/html/wp-content/plugins/faustwp $(docker-compose ps -q wordpress) wp plugin install wp-graphql --activate --allow-root
docker exec --workdir=/var/www/html/wp-content/plugins/faustwp $(docker-compose ps -q wordpress) composer test
composer run docker:stop

…_generate_endpoint

Add apply_filters( 'faustwp_generate_endpoint_search_pattern' ) so
non-standard WordPress installations like Bedrock can customize the
regex pattern used to match the /generate endpoint.

Bedrock returns /wp/generate from site_url() but REQUEST_URI only
contains /generate, causing the preg_match to fail and previews to
404. The filter lets users adjust the pattern without modifying the
plugin source.

Closes wpengine#1872
@latenighthackathon latenighthackathon requested a review from a team as a code owner April 3, 2026 04:56
@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 3, 2026

🦋 Changeset detected

Latest commit: 8c27dce

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

@github-project-automation github-project-automation Bot moved this to 🆕 Backlog in Headless OSS Apr 3, 2026
@ahuseyn ahuseyn moved this from 🆕 Backlog to 👀 In review in Headless OSS Apr 3, 2026
@josephfusco josephfusco moved this from 👀 In review to Community In Review in Headless OSS Apr 15, 2026
@josephfusco
Copy link
Copy Markdown
Member

Thanks for the contribution!

I don't think we need a new filter here. The fix is to use home_url() instead of site_url():

$search_pattern = ':^' . home_url( '/generate', 'relative' ) . ':';

site_url() points to where WordPress core files live (includes /wp/ on Bedrock), while home_url() is the public-facing URL — which is what REQUEST_URI actually contains.

See also #1897 which addresses the same class of Bedrock subdirectory issue on the JS side.

@github-project-automation github-project-automation Bot moved this from Community In Review to ✅ Closed in Headless OSS Apr 20, 2026
@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.

josephfusco added a commit that referenced this pull request May 13, 2026
* fix[faustwp]: (#1872) use home_url() in handle_generate_endpoint

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 #2315, which was closed in favor of
this simpler fix — a new filter is not needed, just the correct URL
helper.

* test[faustwp]: regression test for handle_generate_endpoint() Bedrock case (#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.

* test[faustwp]: tighten AuthCallbacks regression test fidelity

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.

* test[faustwp]: widen AuthCallbacks coverage and document home_url() filter 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.

---------

Co-authored-by: latenighthackathon <latenighthackathon@users.noreply.github.com>
Co-authored-by: Joe Fusco <hello@josephfus.co>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: ✅ Closed

Development

Successfully merging this pull request may close these issues.

Add filter for search_pattern in handle_generate_endpoint

3 participants