When using the Toolset Dynamic Sources API, you can register and provide your own data sources. This way you, can provide additional dynamic sources to blocks that already use this API.

Each dynamic source needs to be represented as an instance of a class that implements the Source interface. This object needs to be added to an array via a hook into the toolset/dynamic_sources/actions/register_sources filter.
Depending on the context, it will be used for providing information about the source (e.g. its name in the select box of some editor block) or for retrieving the actual value when rendering the post where it’s used.
So, the absolute minimum you need to do is:

  1. Create a class that implements the correct interface.
  2. Hook into the above mentioned filter and offer the source.

Absolute minimum
class ExampleSource implements \Toolset\DynamicSources\Sources\Source {
   // a bunch of methods here
}

add_filter( 
    'toolset/dynamic_sources/filters/register_sources',
    function( $dynamic_sources, $post_providers ) {
        $dynamic_sources[] = new ExampleSource();
    }

    return $dynamic_sources;
)

The Source interface

More precisely, the fully qualified name is \Toolset\DynamicSources\Sources\Source.
It defines several methods, which we are going to describe with code examples.

get_name

Should return the unique name (slug) that identifies this dynamic source. It must contain only lowercase letters a-z, numbers, dashes or underscores. To prevent conflicts with other sources, make sure to add a prefix representing your plugin or theme.

get_name
public function get_name() {
        return 'myprefix_example_source';
    }

Return type: string

get_title

Should return the title for this source that can be displayed to clients.

get_title
public function get_title() {
    return __( 'Example source', 'textdomain' );
}

Return type: string

get_group

Should return a group keyword. This allows organizing the sources in the GUI according to where do they take their content from. The value returned by this method must match one of the registered groups, and there are several predefined ones you can use:

  • post\Toolset\DynamicSources\DynamicSources::POST_GROUP
  • author\Toolset\DynamicSources\DynamicSources::AUTHOR_GROUP
  • site\Toolset\DynamicSources\DynamicSources::SITE_GROUP
  • comments\Toolset\DynamicSources\DynamicSources::COMMENTS_GROUP
  • media\Toolset\DynamicSources\DynamicSources::MEDIA_GROUP
  • other\Toolset\DynamicSources\DynamicSources::OTHER_GROUP

get_group
public function get_group() {
    return 'other';
}

Return type: string

Additionally, you can introduce new groups by hooking into the toolset/dynamic_sources/filters/groups filter.

Introduce new groups
add_filter( 
		'toolset/dynamic_sources/filters/groups', 
		function( $groups ) {
			return array_merge( 
				[ 'my-group => __( 'My group', 'example-plugin' ) ], 
				$groups
			);
		}
);

get_categories

Should return the source categories, i.e. the type of content this source can offer. At the moment, there are several acceptable values:

  • text\Toolset\DynamicSources\DynamicSources::TEXT_CATEGORY
  • number\Toolset\DynamicSources\DynamicSources::NUMBER_CATEGORY
  • image\Toolset\DynamicSources\DynamicSources::IMAGE_CATEGORY
  • date\Toolset\DynamicSources\DynamicSources::DATE_CATEGORY
  • audio\Toolset\DynamicSources\DynamicSources::AUDIO_CATEGORY
  • video\Toolset\DynamicSources\DynamicSources::VIDEO_CATEGORY
  • url\Toolset\DynamicSources\DynamicSources::URL_CATEGORY
  • html\Toolset\DynamicSources\DynamicSources::HTML_CATEGORY

get_categories
add_filter( 
		'toolset/dynamic_sources/filters/groups', 
		function( $groups ) {
			return array_merge( 
				[ 'my-group => __( 'My group', 'example-plugin' ) ], 
				$groups
			);
		}
);

Return type: string []

has_fields

The source may either provide a single value or offer a set of fields to choose from. This would be then displayed as another select box under the source selection.
This method needs to return true if you want the source to have fields.

has_fields
public function has_fields() {
    return true;
}

get_fields

If the source uses fields, this method will be used to provide information about them. Each field must be defined as an associative array with these elements:

get_fields
public function get_fields() {
    return [
        [
            'label' => __( 'First field', 'textdomain' ),
            'value' => 'first_field',
            'categories' => $this->get_fields(),
        ],
        [
            'label' => __( 'Second field', 'textdomain' ),
            'value' => 'second_field',
            'categories' => [ 'number' ],
        ],
    ];
}
  • label (string): Display label that will be shown in the select box.
  • value (string): Name of the field, which is unique within this source. Same restrictions apply as for the return value of get_slug().
  • categories (string[]): Categories where this particular field can be used. Has to be a subset of the values returned by get_categories().
  • type, fieldOptions, is_repetitive

Return type: array

is_usable_with_post_provider

Post provider is an object that holds information about the post that should be used for retrieving the actual content from the dynamic source. That doesn’t necessarily have to be the current post, there are for example related posts from Toolset post relationships.

This method gets an instance of PostProvider as the first argument and needs to return a response whether the source can be used within this context.

In most cases, you can probably just return true, but there may be situations when the availability depends on a post type, for example. Please read the chapter about post providers for a more detailed explanation.

is_usable_with_post_provider
public function is_usable_with_post_provider( 
    \Toolset\DynamicSources\PostProvider $post_provider 
) {
    // Make this source show up only for my special post type.
    return in_array( 'my_post_type', $post_provider->get_post_types(), true );
}

Note that at the time when this method is called, you cannot rely on the PostProvider object to provide an actual post yet.

Return type: bool

get_post_provider and set_post_provider

These methods may be used during the processing of the dynamic source. You just need to implement them as a simple getter and setter:

post_provider
public function is_usable_with_post_provider( 
    \Toolset\DynamicSources\PostProvider $post_provider 
) {
    // Make this source show up only for my special post type.
    return in_array( 'my_post_type', $post_provider->get_post_types(), true );
}

get_content

Finally, this method is where the source retrieves the actual value.

When this method is called, the global `$post` variable is set to the post that should be used as the source of the content. That means, you do not have to be concerned with post providers here, as they have already been applied.

This method has two parameters:

  1. $field (string|null): Name of the source field if it’s used, null otherwise.
  2. $attributes (array|null): Reserved for future use.

The method must not print any output, but it is expected to return it.

get_content
public function get_content( $field = null, $attributes = null ) {
    global $post;

    switch( $field ) {
        case 'first_field':
            // This doesn't make much sense as we can just use Toolset to
            // access any custom field value. But it demonstrates 
            // how to retrieve data from a post.
            return get_post_meta( $post->ID, 'my_first_field', true );
        case 'second_field':
            return 42;
        default:
            return '';
    }
}

Return type: string

Minimal example

This is an example that demonstrates a minimal implementation of a custom dynamic source.

Click to expand the code.

Working with post providers

Post provider is an object that holds information about the post that should be used for retrieving the actual content from the dynamic source. That doesn’t necessarily have to be the current post, there are for example related posts from Toolset post relationships.

These two options are available by default. However, if you need to implement a custom post provider, it is possible.

Similarly to dynamic source objects, two things are necessary:

  1. Implement the \Toolset\DynamicSources\PostProvider interface.
  2. Hook into the toolset/dynamic_sources/filters/register_post_providers filter to register it.

Working with post providers
class SpecificPostProvider implements \Toolset\DynamicSources\PostProvider {
    // ...
}

add_filter( 
    'toolset/dynamic_sources/filters/get_post_providers', 
    function( $providers ) {
        $providers[] = new SpecificPostProvider();
        return $providers;
    }
);

PostProvider

The PostProvider interface has only a few methods that need to be implemented.

In the future, additional interfaces may be defined as an optional extension, but this one is not going to be changed.

get_unique_slug

Needs to return a slug that uniquely represents this post provider. Same restrictions and suggestions as for Source::get_slug() apply.

Return type: string

get_label

Label that will be displayed to the user in a select box.

Return type: string

get_post_types

Return slugs of the post types that might be provided through this post provider.

Note that this must be available even during source registration, before any specific post is available.

Return type: string[]

get_post

This method needs to retrieve the post that will be used as a source.

It needs to work only when dynamic content is being generated (not during the source registration).

Alternatively, null can be returned to indicate the post is not available.

Parameters:

  1. $initial_post_id (int): ID of the initial post, which can be used to get the source post for the dynamic content. Initial post is the one being rendered. Do not try to use the current post, as it may not be set in all cases (e.g. REST API requests from the block editor).

Return type: int|null

Example

This is a trivial example that makes any dynamic source always use the page with ID 42.

Post providers example
class SpecificPostProvider implements \Toolset\DynamicSources\PostProvider {

    public function get_unique_slug() {
        return 'myprefix_specific_post';
    }

    public function get_label() {
        return __( 'Post 42.', 'textdomain' );
    }

    public function get_post_types() {
        return [ 'page' ];
    }

    public function get_post( $initial_post_id ) {
        return 42; // assuming post with ID 42 exists and it's a page
    }
}

API filter handbook

Here you can find a list of all available public API filters in one place. Filters not described here are for internal use only and may be subject to change.

toolset/dynamic_sources/filters/register_sources

Filters the dynamic sources that will be available to the user.

Parameters:

  1. Source[] $sources The dynamic sources.
  2. PostProvider[] $post_providers Post providers that are available in the current context.

Return type: Source[]

toolset/dynamic_sources/filters/groups

Filters the groups of the Dynamic Sources offered.

Parameters:

  1. string[] $groups An associative array of groups of dynamic sources. Element key is the group keyword and the value is the display label.

Return type: string[]

toolset/dynamic_sources/filters/source_context

Filter that allows altering the SourceContext object before it is used.

Parameters:

  1. SourceContext $source_context

Return type: SourceContext

toolset/dynamic_sources/filters/register_post_providers

Filter used to register all post providers available within the given source context.

Parameters:

  1. PostProvider[] $post_providers An associative array of post providers indexed by their slugs.
  2. SourceContext $source_context

Return type: PostProvider[]