A provider plugin implements LH_DAV_Collection_Provider and adds an instance on the lh_dav_collection_providers filter. Its methods are the provider’s service API: permission checks live inside them, and tooling plugins (admin screens, MCP abilities) call them rather than the provider’s storage, so a phone and any tool see the same data under the same rules.
interface LH_DAV_Collection_Provider {
public function get_component(); // 'addressbook' or 'calendar'
public function get_collections( $user_id ); // array of collection descriptions
public function get_resource_index( $collection_id, $user_id ); // name => quoted ETag
public function get_resources( $collection_id, $names, $user_id );// name => body
public function put_resource( $collection_id, $name, $body, $user_id ); // new ETag
public function delete_resource( $collection_id, $name, $user_id ); // true
}
add_filter( 'lh_dav_collection_providers', function ( $providers ) {
$providers[] = new My_Contacts_Provider();
return $providers;
} );
Any method may return a WP_Error; a status in its data becomes the HTTP status. Resource names include the extension and must match [A-Za-z0-9._@+-]+.
id (required): slug, unique within its home across all providersowner: 0 for a collection shared by the site, or the owning user’s IDdisplayname, descriptionwritable: whether PUT and DELETE are offeredstate: anything that, when it changes, means every resource must be resent (for example what the viewer may see, or a card format version)site_id (since 0.3.0): the site whose change log feeds the collection, the current site by default. Set it when the data is not per site (network-wide personal data, or another site’s content served on the user’s home site), so changes are recorded and read in one place.color (#RRGGBB), components (default VEVENT; VTODO, VJOURNAL) and, since 0.3.0, order (Apple’s calendar-order)Since 0.3.0 a provider can also implement LH_DAV_Collection_Manager, letting users make collections (MKCALENDAR, or an extended MKCOL per RFC 5689), rename, recolour and reorder them (PROPPATCH) and delete them (DELETE on the collection). LH DAV makes new collections with the first manager in the component whose can_create_collections() says yes, advertises bind on the home when one does, and only lets a user change or delete a collection whose owner is that user.
interface LH_DAV_Collection_Manager {
public function can_create_collections( $user_id ); // bool
public function create_collection( $collection_id, $properties, $user_id ); // true
public function update_collection( $collection_id, $properties, $user_id ); // true
public function delete_collection( $collection_id, $user_id ); // true
}
// $properties: displayname, description, color (#RRGGBB or ''), order, components (create only)
PROPPATCH is all or nothing: if any property cannot be changed none is, and the rest report 424. Colour and order are accepted on any collection, and stored only where the user manages it, so a phone recolouring a read-only calendar sees no error.
Writes through DAV are recorded by LH DAV, against the collection’s site_id. Changes made on the site must be recorded by the provider, against the same site, or devices will not see them on the next sync:
LH_DAV_Change_Log::record( 'addressbook', 0, 'members', '42.vcf', 'modified' ); // or 'deleted'; optional sixth argument: site ID
LH_DAV_Setup_Profile::get_setup_details(): the current user’s server, well-known and principal URLs, homes, username and collections (with item counts). Needs the access capability.LH_DAV_Change_Log::get_entries( $args ): change log rows newest first, filtered by site_id, collection, resource, since, limit (up to 500), plus the latest and pruned-through sequences. Needs install_plugins.LH_DAV_Setup_Profile::return_download_url(): a nonce-carrying setup profile link for the current user, or an empty string. Since 0.3.0 the profile leaves out contacts or calendars when the user has no collections of that kind on the site.LH_DAV_Registry::get_collections(), get_manager() and is_manageable().