From redaxo-structure
Adds and manages custom metadata fields to REDAXO articles, categories, media, and clangs via structure/meta_info plugin. Covers backend config, PHP value access/editing, and programmatic field setup.
How this skill is triggered — by the user, by Claude, or both
Slash command
/redaxo-structure:structure-meta-infoThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
The `structure/meta_info` plugin (ships with the structure addon) lets you add custom fields to:
The structure/meta_info plugin (ships with the structure addon) lets you add custom fields to:
art_* prefix)cat_* prefix)med_* prefix)clang_* prefix)Fields are configured in the backend (Structure → Meta-Information). Each field has a name (matches the SQL column), a label, a type (text, textarea, select, radio, checkbox, legend, date, datestamp, REX_MEDIA_BUTTON, REX_MEDIALIST_BUTTON, REX_LINK_BUTTON, REX_LINKLIST_BUTTON), and an optional default.
The prefix tells REDAXO which entity it belongs to – art_my_field adds a column to rex_article, cat_my_field adds it to rex_article (categories share the table), med_my_field extends rex_media.
// On articles
$article = rex_article::getCurrent();
$value = $article->getValue('art_subtitle');
// On categories
$cat = rex_category::getCurrent();
$value = $cat->getValue('cat_color');
// On media
$media = rex_media::get('hero.jpg');
$copyright = $media->getValue('med_copyright');
// On clang
$clang = rex_clang::getCurrent();
$value = $clang->getValue('clang_currency');
getValue() returns the raw column value as a string. Cast as needed:
$boolField = (bool) (int) $article->getValue('art_featured');
$intField = (int) $article->getValue('art_priority_score');
Through the article/category service so changes are tracked:
rex_article_service::editArticle($articleId, $clangId, [
'art_subtitle' => 'A new subtitle',
'art_featured' => 1,
]);
For media, use rex_media_service::updateMedia(). For clang, write directly via rex_sql (no service wrapper exists for clang updates):
$sql = rex_sql::factory();
$sql->setTable(rex::getTable('clang'));
$sql->setWhere(['id' => $clangId]);
$sql->setValue('clang_currency', 'EUR');
$sql->update();
rex_clang::reset(); // clear in-process clang cache
The meta_info plugin exposes a small API for declaring fields without clicking through the backend. This is the right approach for distributable addons.
<?php
// install.php
if (rex_plugin::get('structure', 'meta_info')->isAvailable()) {
rex_metainfo_add_field(
'rex_articles', // legacy table identifier
'art_subtitle', // field name (must include prefix)
'Subtitle', // label
1, // type_id (1 = text, 2 = textarea, 3 = select, 4 = radio, 5 = checkbox, 6 = REX_MEDIA_BUTTON, 7 = REX_MEDIALIST_BUTTON, 8 = REX_LINK_BUTTON, 9 = REX_LINKLIST_BUTTON, 10 = date, 11 = datestamp, 12 = legend)
'', // params (e.g. dropdown options "1,Yes|0,No")
'', // default
'', // validate regex
['my_addon_perm'] // permission requirement (empty = visible to all)
);
}
The legacy table identifier maps as follows:
| Entity | First arg |
|---|---|
| Article | 'rex_articles' |
| Category | 'rex_categories' |
| Media | 'rex_media' |
| Clang | 'rex_clang' |
(These string names are historic – they don't change with table prefix changes.)
To remove a field on uninstall:
<?php
// uninstall.php
if (rex_plugin::get('structure', 'meta_info')->isAvailable()) {
rex_metainfo_delete_field('art_subtitle');
}
YRewrite ships these by default; they're already added when YRewrite is installed:
art_yrewrite_title – page title overrideart_yrewrite_description – meta descriptionart_yrewrite_index – index / noindexart_yrewrite_canonical_url – canonical overrideart_yrewrite_image – social-share image (REX_MEDIA_BUTTON)Don't redefine them in your own addon.
Meta fields are real columns on rex_article (or rex_media/rex_clang), so you can query them with rex_sql:
$sql = rex_sql::factory();
$sql->setQuery(
'SELECT id FROM ' . rex::getTable('article') . '
WHERE clang_id = :clang
AND status = 1
AND art_featured = 1
ORDER BY priority',
['clang' => rex_clang::getCurrentId()]
);
For dropdowns (type_id 3) the value stored is the option key, not the label. Decoding labels requires re-reading the field config:
$sql = rex_sql::factory();
$sql->setQuery(
'SELECT params FROM ' . rex::getTable('metainfo_field') . '
WHERE name = ?',
['art_status']
);
$params = $sql->getValue('params'); // "1,Draft|2,Review|3,Published"
subtitle won't work; it must be art_subtitle.rex_sql directly instead of rex_metainfo_add_field – the form in the backend doesn't show them.ensureColumn() first.params or store labels redundantly.Creates, edits, and optimizes skills for Claude Code, including drafting, evaluating with test prompts, iterating on performance, and improving skill descriptions for better triggering accuracy.
npx claudepluginhub friendsofredaxo/claude-marketplace --plugin redaxo-structure