Custom providers and listing query types
SkillMediaExtend JetSmartFilters with a custom provider for an unsupported renderer or a custom native JSF Listing query type for a non-post data source. Use when code must register on jet-smart-filters/providers/register or jet-smart-filters/listing/render/query-types/register, extend Jet_Smart_Filters_Provider_Base or the Listing Query_Types Base class, expose custom DOM selectors, merge filter args, or return pagination statistics.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the Custom providers and listing query types skill
What this skill tells your AI
The instructions your AI receives, as published by lonsdale201/wp-agent-skills in jetsmartfilter/jsf-custom-provider-query/SKILL.md and read by ahel’s review.
These are different extension axes:
- A provider teaches JSF where a renderer lives and how to produce its AJAX replacement.
- A query type teaches the native JSF Listing how to fetch and identify items from another data source.
Prefer a query type when the native JSF Listing/card renderer is suitable. Create a provider only when the target renderer itself is unsupported.
Register a provider
The provider base class is loaded immediately before the registration action, so require the subclass inside that action:
add_action(
'jet-smart-filters/providers/register',
static function ( $manager ): void {
require_once __DIR__ . '/class-acme-provider.php';
$manager->register_provider(
Acme_JSF_Provider::class,
__DIR__ . '/class-acme-provider.php'
);
}
);
The subclass must implement get_name(), get_id(),
ajax_get_content(), and get_wrapper_selector(). Override
get_list_selector(), get_item_selector(),
get_wrapper_action(), in_depth(), id_prefix(), or is_data()
only when the renderer needs different behavior.
final class Acme_JSF_Provider extends Jet_Smart_Filters_Provider_Base {
public function get_name() {
return __( 'Acme Catalog', 'acme' );
}
public function get_id() {
return 'acme-catalog';
}
public function get_wrapper_selector() {
return '.acme-catalog';
}
public function get_item_selector() {
return '.acme-catalog__item';
}
public function get_wrapper_action() {
return 'replace';
}
public function in_depth() {
return true;
}
public function ajax_get_content() {
$settings = jet_smart_filters()->data->get_request_var( 'settings' );
$query = jet_smart_filters()->query->get_query_args();
acme_render_catalog(
is_array( $settings ) ? $settings : array(),
is_array( $query ) ? $query : array()
);
}
}
During initial rendering, before JSF localizes frontend settings:
- render a stable wrapper for the query ID;
- store provider settings with
providers->store_provider_settings( $provider, $settings, $query_id ); - store the unfiltered base query with
query->store_provider_default_query( $provider, $args, $query_id ); - publish correct pagination props with
query->set_props( $provider, $props, $query_id ).
Treat request settings and query values as untrusted. Allowlist settings used to select templates or callbacks; never accept an arbitrary PHP callable or file path.
Register a native JSF Listing query type
The query base class is also loaded at its registration action:
add_action(
'jet-smart-filters/listing/render/query-types/register',
static function (): void {
require_once __DIR__ . '/class-inventory-query.php';
\Jet_Smart_Filters\Listing\Render\Query_Factory::register_query_type(
Acme\JSF\Inventory_Query::get_type(),
Acme\JSF\Inventory_Query::class
);
}
);
The class extends
Jet_Smart_Filters\Listing\Render\Query_Types\Base and implements:
- static
get_type()with a stable unique slug; - protected
_get_items()returning an array; get_item_id( $item )returning a stable ID.
Override add_query_args() when recursive array merging is wrong or when a
cached result must be invalidated. Override get_stats() to return accurate
found_posts, max_num_pages, and page; pagination cannot work
correctly with the base class's zero values.
Runtime registration does not add editor controls. A producer must save
type => acme-inventory in the listing query, or a tightly scoped
listing/render/raw-query-args filter must set it for the intended listing.
Acceptance checks
- Provider and query-type IDs do not collide with built-ins.
- Two query IDs on one page remain independent.
- Initial and AJAX markup have the same wrapper contract.
- Empty results return valid markup/data and zeroed props.
- Filter values are normalized and bounded.
- Pagination totals match returned items.
- Rapid requests do not reuse stale cached query results.
- JSF deactivation does not fatal the companion plugin.
References
Verified against JetSmartFilters 3.8.3.1 source:
includes/providers/base.php:15-160includes/providers/manager.php:78-146includes/data.php:198-228includes/filters/manager.php:64-111includes/listing/render/query-factory.php:12-90includes/listing/render/query-types/base.php:12-142includes/listing/render/query-types/posts.php:12-383includes/listing/render/listing-base.php:31-183,335-366
Signals
- GitHub stars
- 22
- Forks
- 2
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
jsf-custom-provider-query- Source
- github.com/lonsdale201/wp-agent-skills