alleyinteractive / alleyinteractive/mantle-framework

`is_within_wordpress_install()` false-positives for wp-content-rooted checkouts, silently disabling `maybe_rsync()` / `with_sqlite()`

Aberta
#906 0 comentários 0 reações 0 responsáveis Ver no GitHub
Linguagem predominante
PHP
Estrelas
28
Forks
7
Merge médio
2d 4h
PRs com merge (30d)
2

Descrição

### Description of the bug

### Summary

`Rsync_Installation::is_within_wordpress_install()` decides whether the framework is
already running inside an installed WordPress by string-matching its own vendored path:

```php
// src/mantle/testing/concerns/trait-rsync-installation.php
public function is_within_wordpress_install(): bool {
return false !== strpos( __DIR__, '/wp-content/' );
}
```

`__DIR__` here is the framework's own install location
(`.../wp-content/.../vendor/alleyinteractive/mantle-framework/...`). In any project laid
out with the repository root **named or nested under `wp-content`** — common in WordPress
VIP / wp-content-rooted monorepos — this string is always present, so the method returns
`true` even when there is **no WordPress core above the checkout**.

Because this method guards several builder calls, they all become silent no-ops.

### Affected version

- `v1.19.3` (ref `d37a354fde52bc27395e86f47295a9b721f8e782`). The check is unchanged on
current `main` at the time of writing.

### Guarded call sites (all early-return `$this` with no error/log)

- `maybe_rsync()`
- `with_vip_mu_plugins()`
- `with_object_cache()`
- `with_sqlite()`

Example:

```php
public function with_sqlite( bool $install = true ): static {
if ( $this->is_within_wordpress_install() ) {
return $this; // <-- silently does nothing for wp-content-rooted repos
}
putenv( 'MANTLE_USE_SQLITE=' . ( $install ? '1' : '0' ) );
// ...
}
```

### Impact

For wp-content-rooted checkouts, `->maybe_rsync_wp_content()->with_sqlite()` in a test
bootstrap **does nothing** — the suite silently runs against the in-place MySQL DB instead
of an rsynced SQLite install. There is:

- **No error and no log line** indicating the calls were skipped, and
- **No public override** to force the "not within an install" branch.

So the documented "Using SQLite for the database" flow
(https://mantle.alley.com/docs/testing/installation-manager#using-sqlite-for-the-database)
is unreachable in these layouts without editing vendored code.

### Reproduction

1. Check out any project whose path contains `/wp-content/` above the vendor dir
(e.g. repo root is `wp-content/`, Mantle at
`wp-content/.../vendor/alleyinteractive/mantle-framework`), with **no `wp-load.php`**
above `wp-content`.
2. Test bootstrap:
```php
use function Mantle\Testing\manager;
manager()->maybe_rsync_wp_content()->with_sqlite()->install();
```
3. Run PHPUnit on the host. **Expected:** rsync to a fresh install + SQLite drop-in.
**Actual:** both calls are no-ops; the suite runs in place against MySQL. No indication
that rsync/SQLite were skipped.

### Root cause

`strpos( __DIR__, '/wp-content/' )` is a proxy for "am I inside a real WP install," but it
matches on a directory *name* rather than the presence of WordPress itself, so it collides
with wp-content-rooted repo layouts.

### Proposed fix (suggestion)

Keep the fast string check as a cheap negative, then confirm an actual WP core exists above
`wp-content`. This also preserves the method's second role as the **rsync recursion guard**
— the rsynced scratch copy *does* have `wp-load.php` above it, so it still reads as "within
an install" and won't re-rsync:

```php
public function is_within_wordpress_install(): bool {
if ( false === strpos( __DIR__, '/wp-content/' ) ) {
return false;
}

$parent = preg_replace( '/\/wp-content\/.*$/', '', __DIR__ );

return is_file( $parent . '/wp-load.php' );
}
```

Alternatives worth considering (maintainer's call):

- Walk up from `__DIR__` looking for `wp-load.php` rather than assuming the `wp-content`
segment is the boundary (handles non-standard core locations).
- Honor an explicit env/override (e.g. `MANTLE_WITHIN_WP_INSTALL=0`) so callers can force
the rsync path deterministically.
- At minimum, `log()`/emit a notice when a guarded call is skipped because the gate is
`true`, so the no-op is not silent.

### Steps To Reproduce

See above.

### Additional Information

_No response_

Guia de contribuição

Abrir o guia de contribuição

Direção de pesquisa

Start in src/mantle/testing/concerns/trait-rsync-installation.php and trace is_within_wordpress_install() through maybe_rsync(), with_sqlite(), and install(). Reproduce with a checkout whose path contains /wp-content/ but has no wp-load.php above it, then run the affected PHPUnit bootstrap. Done when that layout is distinguished from the rsynced install and the SQLite/rsync calls no longer silently no-op.

Escrita pelo modelo de indexação a partir do texto da issue.

Avaliação

Stack de tecnologia
php, sqlite, wordpress
Domínio
backend, databases, testing
Tipo de issue
Bug
Dificuldade
3/5
Tempo estimado
1-2 dias
Status de atividade
Pouca atividade
Clareza
Razoavelmente clara
Facilidade para iniciantes
68/100

Receba novas issues na sua caixa de entrada

Um resumo curto de issues do GitHub para quem está começando.