Skip to main content

Library Filters

This page documents the filters that register library sources and authorize pulls from a shared library.

The library's two permission gates live with the other editor gates: unblock/library/can_use and unblock/library/can_manage.

FilterDescription
unblock/library/sourcesRegister a library source in code
unblock/library/share_accessAuthorize one pull from a shared library

library/sources

Register, modify or remove library sources. Runs once per request, after the core seed and the stored site registry.

ParameterTypeDescription
$sourcesarrayUnblock\Library\Source[] keyed by source id

Returns: the same shape. The array is re-keyed from each entry's own id. A plain array entry is accepted too and built into a site-scoped Source; anything that fails to build is dropped without an error.

Example: Register a Vendor Library

add_filter( 'unblock/library/sources', function( array $sources ): array {

$sources['acme'] = new \Unblock\Library\Source(
id: 'acme',
origin: \Unblock\Library\Origin::Vendor,
scope: \Unblock\Library\Scope::Site,
label: 'Acme Blocks',
url: 'https://patterns.acme.com/library',
interval: 'day',
);

return $sources;

} );

Example: Pin a Trusted Signing Key

This is the only place a vendor origin can be granted the trusted tier. Without a pinned key, its payloads are sanitized before they are cached.

add_filter( 'unblock/library/sources', function( array $sources ): array {

if ( isset( $sources['acme'] ) ) {
$sources['acme'] = $sources['acme']->with_public_key( 'paste-the-vendor-public-key' );
}

return $sources;

} );

Use with_public_keys( array $keys ) to accept an old and a new key during a rotation.

Example: Hide the Official Catalog

add_filter( 'unblock/library/sources', function( array $sources ): array {

unset( $sources['unblock'] );

return $sources;

} );
Common mistake

Trying to pin trust from stored data. A source saved in the unbk_library_sources option is forced site-scoped and has its public_keys stripped on read, and no stored entry can claim the core origin. Pinning works only through this filter or the UNBK_LIBRARY_TRUSTED_KEYS constant. Anywhere else it is ignored without an error, and the source stays in the sanitized tier.

Trust tiers

A library is either trusted or sanitized. Pinning a public key, either through unblock/library/sources above or the UNBK_LIBRARY_TRUSTED_KEYS constant, is what moves one to the trusted tier.

A catalog is trusted only when all four hold. Anything else fails closed to sanitized:

  1. Its index carries an integer version at or above the last one seen (anti-rollback)
  2. Its expires timestamp is in the future (anti-freeze)
  3. X-Unblock-Signature is a valid detached Ed25519 signature over the raw index bytes, against a pinned key
  4. Every fetched document matches the sha256 recorded for it

What the tier changes:

TrustedSanitized
Payload cachedRawPassed through Library\Sanitizer first
Executable JS in patternsKept, gated on unfiltered_html, never auto-executedStripped
PreviewsSandboxed iframeSandboxed iframe

Sanitizing happens before the write to cache, not on read. When a library's trust flips to true, the documents cached at the sanitized tier are dropped, so the next read pulls them raw.

The official catalog ships with its key already pinned, so it is trusted out of the box. Everything else is sanitized until you pin it.

library/share_access

Authorize one pull from a library this site shares. Runs on every request to the sharing routes, after the token has been matched.

Return false to refuse, true to allow. This is where a paid or metered library plugs its own entitlement check.

ParameterTypeDescription
$verdictboolThe built-in verdict: an enabled key holds the token and that key opens the library
$contextarrayRequest context

$context keys:

KeyTypeDescription
librarystringId of the requested library
keystringId of the matched access key, empty when no key matched
tokenstringThe presented access token
sitestringThe consumer's site URL, from X-Unblock-Site
methodstringHTTP method of the request
filestringRequested file, for single-file pulls
filesarrayRequested files, for batch pulls

Example: Refuse Sites Whose Subscription Lapsed

add_filter( 'unblock/library/share_access', function( $verdict, $context ) {

if ( ! $verdict ) {
return $verdict;
}

return acme_subscription_is_active( $context['site'] );

}, 10, 2 );

Example: Open One Library to Everyone

add_filter( 'unblock/library/share_access', function( $verdict, $context ) {

if ( 'free-starters' === $context['library'] ) {
return true;
}

return $verdict;

}, 10, 2 );
This filter has the last word

This filter is the last word on access. Returning true unconditionally serves every library on the site to anyone who finds the share URL. The token match is already done by the time it runs.

Why a refusal looks like a 404

A refused pull answers exactly like an unknown library, so library ids cannot be probed. The precise 401 / 403 is only returned on the discovery route the consumer reconnects through.

Next steps