Extending dynamic data
Add a modifier
A modifier transforms a tag's value. This one turns "Blue Bottle Coffee" into "BBC":
php
use VxFramework\Modules\Dynamic_Data\Modifiers\Base_Modifier;
use VxFramework\Modules\Dynamic_Data\Runtime\Value_Cast;
final class My_Initials_Modifier extends Base_Modifier {
public function key(): string { return 'initials'; }
public function label(): string { return __( 'Initials', 'my-plugin' ); }
public function group(): string { return 'text'; }
public function apply( $value, array $args, array $context ) {
$words = preg_split( '/\s+/', trim( Value_Cast::to_string( $value ) ) );
return strtoupper( implode( '', array_map( fn( $w ) => mb_substr( $w, 0, 1 ), array_filter( $words ) ) ) );
}
}
add_filter( 'vxframework/dynamic-data/modifiers', function ( array $modifiers ) {
$modifiers['initials'] = new My_Initials_Modifier(); // keyed by key()
return $modifiers;
} );Use it as @post(title).initials(). It appears in the Advanced editor's modifier list and autocomplete.
Useful optional methods:
args(): describe arguments, as[ [ 'key' => 'length', 'label' => 'Length', 'type' => 'number', 'default' => 10 ] ], so the editor can offer inputs.applies_to(): which value types the modifier is offered for (string,number,url,date,boolean,list).client_resolvable(): returnfalseif the editor can't run your modifier in the browser. Custom modifiers always run on the server; previews wait for it.
Add a tag group
A group adds a new @group(...) root, for data VX doesn't know about:
php
use VxFramework\Modules\Dynamic_Data\Runtime\Groups\Base_Group;
use VxFramework\Modules\Dynamic_Data\Runtime\Resolved_Value;
final class My_Weather_Group extends Base_Group {
public function get_key(): string { return 'weather'; }
public function get_label(): string { return 'Weather'; }
public function resolve( array $path, array $context ): ?Resolved_Value {
$data = my_weather_lookup(); // e.g. [ 'current' => [ 'temp' => 21 ] ]
foreach ( $path as $segment ) {
if ( ! is_array( $data ) || ! array_key_exists( $segment, $data ) ) {
return null; // unknown path renders empty
}
$data = $data[ $segment ];
}
return new Resolved_Value( $data, is_numeric( $data ) ? 'number' : 'string' );
}
}
add_filter( 'vxframework/dynamic-data/groups', function ( array $groups ) {
$groups['weather'] = new My_Weather_Group();
return $groups;
} );Then write Currently @weather(current.temp)° in the Advanced editor. Custom groups resolve on the server.
Add a builtin
Builtins compute values and start with #, like #math. Register them through vxframework/dynamic-data/builtins, the same way as modifiers (keyed by name). Look at #query_var in VX's source for the shape.
Render expressions from PHP
php
use VxFramework\Modules\Dynamic_Data\Expression;
echo esc_html( Expression::render( 'Rated @post(rating) of 5', [ 'post_id' => get_the_ID() ] ) );
$tagline = Expression::render_nullable( '@post(tagline)', [ 'post_id' => $id ] ); // null when emptyPass post_id (for @post and @author), term_id and taxonomy (for @term), and user_id (for @user).
Change which blocks can be bound
vxframework/dynamic-data/supported-blocks filters the final map of bindable blocks and attributes, and vxframework/dynamic-data/block-overrides adds per-block allow, deny or restrict entries. Custom blocks with attributes that have the content role are picked up automatically.
Technical details for LLMs
Base_Modifier(VxFramework\Modules\Dynamic_Data\Modifiers): abstractkey(),label(),apply( $value, array $args, array $context ); optionalgroup()(defaultgeneral),applies_to()(constantsAPPLIES_TO_SCALAR,APPLIES_TO_STRING),args(),client_resolvable()(default true; set false unless a JS twin exists),passes()for conditional modifiers. The filter map must be keyed by the modifier key; non-string keys and non-Base_Modifiervalues are discarded.defaultis registered as an alias offallback.Base_Group(…\Runtime\Groups):get_key(),get_label(),resolve( array $path, array $context ): ?Resolved_Value. Stateless; context carries the entity. Map keyed by group key.- Builtins:
vxframework/dynamic-data/builtinsmap keyed by name (math,query_varbuilt in). - Context keys for
Expression::render:post_id,term_id,taxonomy,user_id, plusmeta_overlay/core_overlay(unsaved values, used by editor previews). - Custom groups aren't guaranteed to appear in the tag picker catalog;
vx-framework/get-dynamic-data-catalogreflects VX's built-in groups.