Property Types
A Property Type is a kind of structured value (Glossary): a PHP class, a projection per store, and frontend components.
Backend class
Implement PropertyType, paired with a class extending PropertyDefinition that holds the type-specific definition fields, and register it with NeoWikiRegistrar::addPropertyType(). Example: src/ColorType.php and src/ColorProperty.php.
PropertyType::validate() returns Violation[]. NeoWiki runs no validation in the browser; the input component shows the violations the server returns, each code resolved to the message key neowiki-field-<code>, which your extension defines (RedHerb's i18n/en.json).
Projection
Statements of a Property Type without a Neo4j value builder are omitted from the Neo4j projection; without an RDF value mapper, from the RDF export.
For Neo4j, register a builder that converts the Value to Neo4j scalars under the Property Type name:
$registrar->addNeo4jValueBuilder( ColorType::NAME, static fn ( $value ) => $value->toScalars() );For the RDF export, register a mapper under the Property Type name with NeoWikiRegistrar::addRdfValueMapper(). It receives the Statement's NeoValue and returns a list of RDF terms — Literals, or Iris for values that denote a resource, as the built-in url mapper does — one per value part. Guard the value shape: the mapper receives whatever a Statement holds. RedHerb's RedHerbHooks.php registers a guarded mapper for its color type.
Frontend components
Register the type's components through the neowiki.registration JS hook from your frontend module:
const nw = require( 'ext.neowiki' );
mw.hook( 'neowiki.registration' ).add( ( registrar ) => {
registrar.registerPropertyType( {
typeName: 'color',
valueType: nw.ValueType.String,
displayAttributeNames: [],
createPropertyDefinitionFromJson: function ( base, json ) {
return Object.assign( {}, base, {
allowedColors: Array.isArray( json.allowedColors ) ? json.allowedColors : []
} );
},
getExampleValue: function () {
return nw.newStringValue( '#ff5733' );
},
displayComponent: ColorDisplay,
inputComponent: ColorInput,
attributesEditor: ColorAttributesEditor,
label: 'myext-property-type-color',
icon: icons.cdxIconHighlight
} );
} );The registration object's shape is defined by PropertyTypeRegistration.ts; every field is required, including attributesEditor even for a type with no configurable attributes. typeName must equal the backend PropertyType::getTypeName(); createPropertyDefinitionFromJson( base, json ) extends the common definition base with the type-specific fields your PropertyDefinition class serializes; label is a message key your module registers. The components conform to ValueDisplayContract.ts, ValueInputContract.ts, and AttributesEditorContract.ts.
icon is a Codex Icon: a stock icon from the gallery, declared via CodexModule::getIcons as RedHerb's extension.json does, or an SVG string.
Full example: resources/init.js with ColorDisplay.vue, ColorInput.vue, and ColorAttributesEditor.vue.