Blog Sections Open
Creating Documents Programmatically with TV Values in MODX Revo
Creating resources from code is straightforward in Revo, but TVs are not regular resource fields, so they need their own save step.
The old code example already showed how to create a resource programmatically in MODX Revo, but it stopped at the point where many developers get confused: TVs are not saved with a simple set() call like normal resource fields.
The Base Resource Creation Example
$document = $modx->newObject('modResource');
$document->set('createdby', $modx->user->get('id'));
$document->set('template', 3);
$document->set('isfolder', 0);
$document->set('published', 1);
$document->set('createdon', time());
$document->set('pagetitle', 'Artificial document');
$document->set('alias', 'artificial-document');
$document->set('description', '<p>Short article description.</p>');
$document->set('introtext', '<p>Short article intro.</p>');
$document->setContent('<p>Full article text</p>');
$document->set('parent', 21);
$document->save();
Why TVs Need a Separate Step
TVs are stored through a related table, not as direct columns on the resource. That means this will not work reliably:
$document->set('my_tv', 'value');
Instead, save the resource first and then assign TVs explicitly.
The Correct Pattern
$document->save();
$document->setTVValue('my_tv', 'value');
$document->setTVValue('color', 'blue');
$document->setTVValue('price', '199');
Why This Matters
Programmatic resource creation is often used for imports, catalog synchronization, CRM-driven content, or frontend submission flows. In all of those cases, forgetting the extra TV save step leads to resources that look complete in code but arrive in the manager without the expected custom field data.
The safe rule is simple: create the resource, save it, then write TVs through setTVValue().
Using Login Across Two Different Contexts in MODX Revo
How to think about Login and multiple contexts in Revo when one request initializes one context and another context must also participate in authentication.
Making AjaxSearch Work with Content Rendered Through Ditto
Why AjaxSearch does not automatically search the rendered output of Ditto, and what to do when most site content is assembled from hidden source documents.