Virtual Pages
How to create dynamic pages without modResource — the clean, modern way.
Why would you need this?
In traditional MODX, every document is a resource in the tree. It works fine, but:
- It becomes messy for large catalogs or dynamic content
- You're forced to use TVs, chunks, and rigid templates
- You can’t fully control logic or structure
PageBlocks changes that. You define how to handle URLs, what data to load, and what template to render — all through controllers.
What is a virtual page?
A virtual page is:
- Not created in the MODX resource tree
- Available at a custom URL (e.g.,
/product/macbook-pro) - Fully managed by a controller
- Built from any data — database, API, cache, etc.
Example — Product page
Let’s say you have a products table. You want to open a product page by its alias, like /product/macbook.
1. Define a route (routes/web.php):
php
Route::get('/product/{alias}', [ProductController::class, 'show']);2. Create a controller (ProductController.php):
php
class ProductController extends Controller
{
public function show($alias)
{
$product = $this->modx->getObjct(\pbTableValue::class, ['alias' => $alias]);
if (!$product) {
return $this->abort(404);
}
return $this->view('templates/product', ['product' => $product->toArray()]);
}
}3. Create a template (templates/product.tpl):
html
<h1>{$product.name}</h1>
<div>{$product.description}</div>
<p>Price: {$product.price}</p>Why controllers rock
- No dependency on modResource — you control structure entirely
- Better performance — no TVs, chunks, or unnecessary logic
- Flexible logic — access control, redirects, SEO, error handling
- Template freedom — write clean Fenom views without limitations
- Custom URLs — support any route structure and dynamic segments
Where virtual pages shine
- Product catalogs with thousands of items
- User profiles like
/user/boshnik - Blog articles from a custom table
- Multilingual URLs like
/en/blog/title - AJAX/API endpoints like
/api/products/42 - Dynamic filters like
/catalog/sale/smartphones
Conclusion
Controllers in PageBlocks = full MVC inside MODX. You gain Laravel-like control and flexibility while staying within the MODX ecosystem. No more relying on modResource. Just clean logic, custom structure, and full freedom.