Skip to content

🖼️ View

The View class in PageBlocks is a wrapper around the Fenom templating engine, providing a simple yet powerful way to render templates: MODX chunks, .tpl files, @INLINE templates, and more.

🚀 Quick Start

You can render a template with data:

php
use Boshnik\PageBlocks\Facades\View;
View::make('@INLINE <p>{$title}</p>', ['title' => 'Homepage']);

Or using the helper function:

php
view('file:templates/base.tpl', ['title' => 'Homepage']);

💡 Controller Example

php
Route::get('/', function () {
    return view('file:templates/base', ['name' => 'PageBlocks']);
    // => looks for: core/App/elements/templates/base.tpl
});

🔧 Snippet Example

Let's say you have a MyProfile snippet that displays the current user's profile:

php
<?php
$user = $modx->user;
return view('file:blocks/profile.tpl', [
    'username' => $user->get('username'),
    'email'    => $user->getOne('Profile')->get('email'),
]);

Chunk core/App/elements/blocks/profile.tpl:

php
<div class="profile">
    <h2>{$username}</h2>
    <p>Email: {$email}</p>
</div>

📄 Template Types

Where it looksExample
Inline template code (@INLINE)view('@INLINE Hello, {$name}')
File template (@FILE, file:)view('@FILE blocks/card.tpl')
MODX template (template:)view('template:base')
Default: first modChunk, then fileview('header')

If no extension is specified, .tpl is automatically added for files.

⚙️ Settings

SettingDescriptionDefault Value
pageblocks_elements_pathPath to file templates relative to core/ folder. Used for @FILE and file: templates.App/elements/
pageblocks_file_elements_onlyIf true, templates are loaded only from files, MODX chunks are ignored. Improves performance.false
pageblocks_fenom_auto_reloadAutomatic template recompilation when files change. Can be disabled in production for better performance.true

📁 Template Storage

When using file: or @FILE, the path is relative to the pageblocks_elements_path directory.

Example:

php
view('file:blocks/article.tpl');
// => looks for: core/App/elements/blocks/article.tpl

📦 Available Data

🧠 $modx

Templates have access to the global $modx object, identical to the one in PHP code. This allows accessing resources, current user, and other system data directly from templates:

🔹 Current Document

php
{$modx->resource->id}         {* Current page ID *}
{$modx->resource->pagetitle}  {* Document title *}
{$modx->resource->get('template')} {* Getting any field *}

🔹 Current User

php
{$modx->user->username}
{$modx->user->id}
{$modx->user->get('email')}
{$modx->user->getGravatar()}

💬 Flash Messages

Passed through $_SESSION['pageblocks']['flash']. Available in templates:

  • old_input - previous form field values
  • errors - short error messages per field (one error per field)
  • errors_full - all error messages per field
  • success_message - success notification
  • error_message - error notification

Examples:

php
{if $errors.email}
  <p class="error">{$errors.email}</p>
{/if}

<input type="text" name="email" value="{$old_input.email}">

{if $success_message}
  <div class="alert alert-success">{$success_message}</div>
{/if}

{if $error_message}
  <div class="alert alert-danger">{$error_message}</div>
{/if}

To display all errors:

php
{foreach $errors_full as $field => $list}
  {foreach $list as $msg}
    <p class="error">{$msg}</p>
  {/foreach}
{/foreach}

💡 All flash data is cleared after first display.

🧩 Modifiers

PageBlocks extends Fenom's capabilities with modifiers - small functions that can be applied directly in templates. They make templates more concise and flexible.

🛠 How to Add Custom Modifiers

You can add custom modifiers in:

html
core/App/Helpers/fenom/modifiers.php

This file should return an array like:

php
return [
    'upper' => function($value) {
        return mb_strtoupper($value);
    },
    'users' => function () {
        return query('modUser')
            ->alias('user')
            ->select('user.*,profile.*')
            ->where(['active' => 1])
            ->join('modUserProfile', 'profile', 'user.id = profile.internalKey')
            ->get();
    },
];

Calling Modifiers in Templates

  • As a value filter:
php
<h2>{$title|upper}</h2>
  • As a function:
php
{users()}

This will return a list of all active users with their profiles.

Inside the function, $this->modx is available - the current MODX instance.

🔧 Default Modifiers

PageBlocks includes many useful modifiers out of the box:

NameDescription
routeGet path by route name: {route('home')}
langGet translation from dictionary: {lang('title')}
configGet config from Config or MODX: `{'site_name'
urlGenerate link by resource ID: `{1
lexiconGet phrase from MODX lexicon
resourceGet field or all data of a resource by ID
userGet user field by ID or current user
chunkInsert MODX chunk: `{'header'
snippetExecute MODX snippet: `{'getResources'
buttonAutomatic button generation
notagsRemove HTML tags: {notags($text)}
isloggedinCheck if user is logged in
ismemberCheck if user is in a group
phoneClean string to phone number format
pbJsonSimplified call to pbJson snippet for serialization
cssToHeadAdd CSS to <head>
jsToBottomAdd JS to document bottom
preg_replaceRegex replacement
printOutput debug information in <pre>

⚡ Pseudo-Tags

You can create custom pseudo-tags (inline functions) that work like regular Fenom functions:

php
{icon 'edit' class='icon-sm'}

These tags are convenient replacements for long insert or include statements, especially for repetitive HTML fragments like icons, buttons, or badges.

📁 Storage Location

Create a file:

html
core/App/Helpers/fenom/inline_tags.php

It should return an array of names and functions:

php
return [
    'icon' => function($params) {
        $name = array_shift($params);
        $attrs = [];

        foreach ($params as $key => $value) {
            $attrs[] = htmlspecialchars($key).'="'.htmlspecialchars($value).'"';
        }

        $attrStr = $attrs ? ' ' . implode(' ', $attrs) : '';

        $path = MODX_BASE_PATH . "assets/icons/{$name}.svg";
        if (!file_exists($path)) {
            return "<!-- icon '{$name}' not found -->";
        }

        $svg = file_get_contents($path);
        return preg_replace('/<svg\b(.*?)>/', '<svg$1' . $attrStr . '>', $svg, 1);
    },
];

✨ Template Examples

php
{icon 'edit' class='icon-sm text-muted'}
{icon 'user' class='icon-lg' aria-hidden='true'}

These functions don't require insert or include declarations, are easier to read, and scale well.

🧱 Block Tags

Block tags allow wrapping template content in conditional blocks. Content inside will only be displayed if the condition is met.

This is especially useful for controlling access to template parts - like showing menus only to logged-in users or admins.

✅ Usage Example

php
{auth}
    <a href="/profile">Profile</a>
{/auth}

{guest}
    <a href="/login">Login</a>
{/guest}

In this example:

  • {auth} block works only for authenticated users
  • {guest} block - only for guests

🧩 How to Add a Block Tag

Block tags are loaded from:

html
core/App/Helpers/fenom/block_tags.php

You can add a new tag like superadmin that shows content only for user with ID = 1:

php
return [
    'superadmin' => function (array $params, $content) {
        if ($this->modx->user->id === 1) {
            return $content;
        }
    },
];

📦 Usage Example

php
{superadmin}
    <div class="alert alert-danger">
        You're a super-admin!
    </div>
{/superadmin}

Content inside will only show if the user is a super-admin.

📘 How It Works

A block tag is a function that receives:

  • $params - parameters passed to the tag
  • $content - content between opening and closing tags

🌍 Global Variables

Fenom supports global variables accessible from any template. Useful for static data, settings, or common values like project name, support email, assets path etc.

🛠 How It Works

File core/App/Helpers/fenom/data.php should return an array with needed data:

php
return [
    'package' => 'PageBlocks',
    'support_email' => 'support@example.com',
];

This array will be available in templates as global object $.pb.

📦 Template Usage Example

php
{$.pb.package}        {* Outputs: PageBlocks *}
{$.pb.support_email}  {* Outputs: support@example.com *}

Global variables are in the pb scope, so access them via {$.pb.key}.

🔐 PHP Functions

By default Fenom supports a limited set of safe PHP functions callable directly in templates:

✅ Default Available Functions

FunctionPurpose
count()Count array elements
is_string()Check if variable is a string
is_array()Check if variable is an array
is_numeric()Check if variable is a number
is_int()Check for integer
constant()Get constant value
is_object()Check if variable is an object
gettype()Get variable type
is_double()Check for float
strtotime()Convert string to timestamp
json_encode()Convert data to JSON
json_decode()Decode JSON string
ip2long()IP → integer
long2ip()Integer → IP
strip_tags()Remove HTML tags
nl2br()Convert \n to <br>
explode()Split string by delimiter
implode()Join array into string

🧠 Usage Example

php
{count($items)} items
{json_encode(['foo' => 'bar'])}
{strtotime("2025-01-01")}
{strip_tags($html)}

➕ Allowing Additional Functions

You can allow other safe functions:

core/App/Helpers/fenom/php_functions.php:

php
return [
    'lcfirst',
    'mb_strlen',
    'htmlspecialchars',
];

⚠️ Security

Never allow dangerous functions like:

  • eval, exec, system, shell_exec
  • file_get_contents, fopen, unlink

They could lead to data leaks or remote code execution.

Only allow pure, predictable functions that don't interact with filesystem, network or environment.

🧪 Output Processing

The third argument of View::make() or view() helper is an output processor.

Useful for:

🔹 Removing HTML

php
view('user-card.tpl', ['user' => $user], function ($buffer) {
    return strip_tags($buffer);
});

📄 Result: clean text without <div>, <a> etc. - good for text emails.

🔹 HTML Minification

php
view('page.tpl', [], function ($buffer) {
    return preg_replace('/\s{2,}|\n/', '', $buffer);
});

📉 Removes spaces and newlines - speeds up page load.

🔹 Automatic Censorship

php
view('comment.tpl', ['text' => $comment], function ($buffer) {
    return str_ireplace(['fool', 'idiot'], '[censored]', $buffer);
});

🛡️ Useful for user content moderation.

🔹 Replacing Absolute Paths

php
view('page.tpl', [], function ($buffer) {
    return str_replace('https://example.com/assets/', '/assets/', $buffer);
});

🔁 Helpful when moving sites between environments.

php
view('page.tpl', [], function ($buffer) {
    return preg_replace('/<a (.*?)href="(.*?)"(.*?)>/i', '<a $1href="$2" rel="nofollow"$3>', $buffer);
});

🔍 Protects against SEO spam, especially in comments or guest content.

🧮 Query Builder

Templates have access to the query() helper - a wrapper for pbQuery. You can run database queries directly from Fenom templates.

📊 Counting Records

php
{query('modResource')->where(['published' => 1])->count()}

📋 Get Resource List

php
{set $resources = query('modResource')
    ->where(['template' => 4])
    ->sortBy('menuindex')
    ->limit(5)
    ->fetchAll()
}
<ul>
    {foreach $resources as $res}
        <li><a href="{$res.uri}">{$res.pagetitle}</a></li>
    {/foreach}
</ul>

🔀 Using join

php
{set $users = query('modUser')
    ->alias('u')
    ->where(['u.active' => 1])
    ->join('modUserProfile', 'p', 'u.id = p.internalKey')
    ->select('u.username, p.fullname')
    ->sortBy('u.username')
    ->fetchAll()
}
{foreach $users as $user}
    <p>{$user.username} ({$user.fullname})</p>
{/foreach}

🔍 Find Record by ID

php
{set $resource = query('modResource')->find(10)}
{if $resource}
    <h2>{$resource->pagetitle}</h2>
{/if}

📂 Get Categories Array

php
{set $categories = query('modCategory')->fetchAll()}
<ul>
    {foreach $categories as $cat}
        <li>{$cat.category}</li>
    {/foreach}
</ul>

🔧 Using value() or pluck()

php
{query('modResource')->where(['id' => 5])->value('pagetitle')}
php
{set $titles = query('modResource')
    ->where(['parent' => 0])
    ->pluck('pagetitle')
}
<pre>{$titles|print}</pre>

📁 File Structure

App/
└── Helpers/
    └── fenom/
        ├── modifiers.php         ← Modifiers
        ├── inline_tags.php       ← Pseudo-tags
        ├── block_tags.php        ← Block functions
        ├── data.php              ← Global data
        └── php_functions.php     ← Allowed PHP functions

🧼 Cache Clearing

When you clear cache via MODX manager, this automatically runs:

php
View::clearCache();

This clears all compiled Fenom templates.

© PageBlocks 2019-present