Skip to content

Resources outside the tree

A page that behaves like a MODX resource — its own URL, template, menu flags, publishing, blocks — but lives in pb_resources instead of site_content, and therefore never appears in the resource tree.

Why not just make a resource

The MODX tree is a manager tool. It is fine for the pages a person navigates: sections, articles, landing pages. It stops being fine when the pages are data.

Ten thousand cities, every company in a directory, every vacancy — as resources, they turn the tree into something nobody can open, slow down the manager, and bury the two dozen pages an editor actually edits.

Those pages still need everything a resource has: an address, a template, a title, meta, publishing. pb_resources gives them exactly that, in their own table.

What it can do

The columns mirror the ones you know:

Contentpagetitle, longtitle, description, introtext, content, menutitle
Addressalias, uri, uri_override, alias_visible
Behaviourtemplate, menuindex, hidemenu, isfolder, searchable, context_key
Lifecyclepublished_at, deleted_at, timestamps

Plus the constructor pair — model_type and model_id for the owner, constructor_id, field_id and data. Which means a custom resource is an AbstractDataModel: constructor fields work on it, exactly as they do on a block.

It also has blocks(), so a page here is assembled in the builder like any other.

Creating one

A custom resource is a table row whose model is PbResource.

  1. PageBlocks → Constructor → Tables, create a table.
  2. In Model pick PbResource instead of PbTableData. That is what gives the row its resource columns — address, template, meta.
  3. On the Fields tab describe what you need beyond them: a city's area, a vacancy's salary, a company's phone number.
  4. On the Columns tab, what to show in the list so an editor can find things.

The table constructor itself is covered in Tables.

Where to edit them

Where you created them: rows open in that table's grid. To an editor it is an ordinary list with search and filters rather than a resource tree — and ten thousand rows behave like ten thousand rows, not like ten thousand pages.

Output

Two different cases, not to be confused.

A single page opens by itself. The address resolves exactly as a normal resource's does: a visitor asks for /cities/kazan, ResourceResolver finds the row and renders it with the template from the template column. Nothing needs calling — the template sees the same fields a resource has, plus the constructor's own.

A list is built by a snippet. That needs pbList with the model named:

[[!pbList? &model=`PbResource` &parent=`[[*id]]` &tpl=`chunk:cityItem` &limit=`20`]]

Not to be confused with pbResources

pbResources lists MODX resources from site_content. It cannot see custom ones — different table. For those, pbList with model='PbResource'.

Example: a directory of cities

A catalogue of a thousand cities. Each needs its own address /cities/kazan, a title, a description for search engines, and a couple of fields of its own — region and population.

As MODX resources that is a thousand rows in a tree nobody can open afterwards. As custom resources it is one table in the constructor: a searchable list for the editor, ordinary addresses for the visitor, and the tree stays what it was — the couple of dozen pages people actually edit by hand.

The catalogue section itself stays a real resource: there is one of it, people edit it, it belongs in the tree.

How the address is resolved

ResourceResolver looks in three places, in order:

  1. a translation — so /de/uber-uns is the canonical German address;
  2. site_content — an ordinary MODX resource;
  3. pb_resources.

Both kinds render through the same templates. A template does not know, and does not need to know, which table its page came from.

A real resource wins a collision

If an address exists in both tables, site_content answers. That makes the custom table safe to fill from an import: a generated row cannot take over a page an editor made.

The URI builds itself

uri is recomputed on save from the alias and the owner's prefix, so you set alias and forget about it.

Two switches change that:

  • uri_override — keep the uri exactly as written and stop recalculating it. For an address inherited from an old site that must not change.
  • alias_visible on the parent — when off, the parent's alias is left out of the child's URI. That is how a grouping level exists in the data without showing up in the address.

When to use which

Use
A page an editor writes and rearrangesA MODX resource
Many pages generated from data, each needing its own URL and metapb_resources
A page with logic and no stored row at allA virtual page

The three coexist. A catalog section can be a resource, its thousands of items custom resources, and its filter a virtual page — on the same site, in the same templates.

© PageBlocks 2019-present