# Radicle 2: Using Eloquent Models alongside WP_Query, caching, pagination, and extensibility.

**URL:** https://discourse.roots.io/t/radicle-2-using-eloquent-models-alongside-wp-query-caching-pagination-and-extensibility/30314
**Category:** radicle
**Tags:** eloquent, models
**Created:** 2026-04-17T11:41:48Z
**Posts:** 3

## Post 1 by @Stackie — 2026-04-17T11:41:48Z

Hi Roots,

We’re working with Radicle 2 and using `Illuminate\Database\Eloquent\Model` alongside WordPress.

I have a few questions / concerns about how this integrates with WordPress internals (`WP_Query($args)`), especially in when extending the query $args. For example in combination with pagination or with plugins like FacetWP.

* * *

**(1.) WP\_Query integration with Eloquent models**

Is it possible (or intended) to integrate Eloquent model queries with `WP_Query` arguments?

An Eloquent model is not related to `WP_Query` by default. In order to opt in to WordPress core functionality such as pagination or WP\_Query-style arguments, we currently handle it like this:

```
class Employee extends Model
{
    public static function byTermId(int $termId, ?string $taxonomy = null, int $limit = -1): Collection
    {
        if (empty($taxonomy)) {
            return collect();
        }

        $postIds = get_posts([
            'post_type' => 'employee',
            'post_status' => 'publish',
            'posts_per_page' => $limit,
            'fields' => 'ids',
            'facetwp' => true,
            'tax_query' => [
                [
                    'taxonomy' => $taxonomy,
                    'field' => 'term_id',
                    'terms' => $termId,
                ],
            ],
        ]);

        if (empty($postIds)) {
            return collect();
        }

        return static::query()->whereIn('ID', $postIds)->get();
    }
}
```

Ideally, we would like to express this kind of query more naturally alongside the model itself, instead of splitting logic between `get_posts()` / `WP_Query` and Eloquent.

Is this something that is intended or recommended within Radicle? Or is there a known limitation / best practice / design pattern when comparing or combining these two approaches?

* * *

**(2) Query caching for Eloquent models**

Is there any built-in support for caching Eloquent model queries in this setup, or is caching expected to be handled separately (e.g. WordPress object cache, transients, or a custom caching layer)?

Is this something that is intended or recommended within Radicle? Or is there a known limitation / best practice / design pattern?

* * *

Any guidance or best practices on how to structure this cleanly in Radicle 2 would be greatly appreciated.

Looking forward to your insights.

Best regards,  
Lex

---

## Post 2 by @ben — 2026-04-17T15:32:54Z

Hey @Stackie, thanks for the topic! Short version: Radicle ships the Eloquent models as a convenience, not a `WP_Query` replacement

`WP_Query` keeps owning what it should: `tax_query`/`meta_query` operators, `pre_get_posts`, FacetWP, archive pagination with rewrite rules and `max_num_pages`, anything that hooks query vars. Use Eloquent where owning the query surface matters: API endpoints, admin tools, reports, complex joins, scopes, observers.

Your `get_posts(['fields' => 'ids']) -> Employee::whereIn('ID', $ids)` is the usual pattern, and there are two gotchas: `whereIn` doesn’t preserve the order `WP_Query` returned, and you lose `found_posts`/`max_num_pages` which kills archive pagination.

I’ve got an open PR that handles both: `Post::fromWpQuery($args)->with('meta')->get()` runs the `WP_Query`, hydrates Eloquent in order, returns a `LengthAwarePaginator` aligned with `paged` for archive/taxonomy/search contexts, static front-page pagination can use `page`. Subclasses (`Seed`) inherit it: [https://github.com/roots/radicle/pull/337](https://github.com/roots/radicle/pull/337)

If you want taxonomy queries native in Eloquent you’d still need `Term`/`TermTaxonomy`/`TermRelationship` models and the plumbing (tracking as a follow-up issue: [https://github.com/roots/radicle/issues/338](https://github.com/roots/radicle/issues/338))

Caching: wrap with `Cache::tags('wp-posts')->remember(...)` through Acorn. Same PR adds a provider that flushes the tag on `save_post`/`deleted_post`/term writes (Redis/memcached, graceful fallback) — configurable via `config/wp-cache.php` or `WP_CACHE_INVALIDATION`.

---

## Post 3 by @Stackie — 2026-04-23T07:40:40Z

Hey Ben, thanks a lot for the detailed explanation — really helpful.

I’m looking forward to the new release with `fromWpQuery()`, WP cache invalidation, and the addition of `Term`, `TermTaxonomy`, and `TermRelationship`. That should make things a lot smoother to work with.

Appreciate you taking the time to share all this!
