@prefix sioc: <http://rdfs.org/sioc/ns#> .
@prefix dc: <http://purl.org/dc/elements/1.1/> .
@prefix dcterms: <http://purl.org/dc/terms/> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
@prefix content: <http://purl.org/rss/1.0/modules/content/> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .

<https://lhero.org/portfolio/lh-vcard/>
  a sioc:Post ;
  dc:title "CardDAV Address Book" ;
  dcterms:identifier 150066 ;
  dc:modified "2026-10-13T00:02:37Z"^^xsd:dateTime ;
  dc:created "2026-10-13T00:02:37Z"^^xsd:dateTime ;
  sioc:link <https://lhero.org/portfolio/lh-vcard/carddav-address-book/> ;
  sioc:has_creator <https://lhero.org/author/1/#account> ;
  sioc:has_container <https://lhero.org/#posts> ;
  content:encoded "<ul class=\"lh_portfolio-meta\"><li><strong>Part of:</strong> <a href=\"https://lhero.org/portfolio/lh-vcard/\">LH Vcard</a></li></ul><p class=\"wp-block-paragraph\">Since 1.10.0 each site&#8217;s members are also available as a read-only CardDAV address book, so staff can sync the whole club into their phone or desktop contacts instead of downloading cards. It replaced the separate LH CardDAV Server plugin, which was retired. A synced card is built by the same code as a downloaded one, so both always carry the same data.</p><h2 class=\"wp-block-heading\">Setting it up</h2><p class=\"wp-block-paragraph\">You need the capability that shows vCard links (<code>publish_posts</code> by default) and an <strong>application password</strong> (Users → Profile → Application Passwords). Your normal account password is not accepted.</p><ul class=\"wp-block-list\"><li><strong>iPhone:</strong> Settings → Apps → Contacts → Contacts Accounts → Add Account → Other → Add CardDAV Account. Server is the site&#8217;s domain (e.g. <code>princesparktouch.com</code>), then your username and the application password.</li><li><strong>Android (DAVx5):</strong> Login with URL and user name, using <code>https://</code> plus the site&#8217;s domain.</li><li><strong>Thunderbird:</strong> New CardDAV address book, using <code>https://</code> plus the site&#8217;s domain.</li></ul><p class=\"wp-block-paragraph\">Apps find the address book on their own through <code>/.well-known/carddav</code>. If one does not, give it the full address: the site&#8217;s domain followed by <code>/carddav/</code>.</p><h2 class=\"wp-block-heading\">What is in it</h2><ul class=\"wp-block-list\"><li>Every member of the site, except members blocked on it (LH Buddypress Block Members).</li><li>Teams are the BuddyPress groups the person syncing can see: public and private groups always, hidden groups only for their own members and BuddyPress moderators. Downloads follow the same rule for whoever generated the link.</li><li>It is read-only. Contacts apps cannot edit or delete cards; the site is the only place to change member details.</li></ul><h2 class=\"wp-block-heading\">How syncing works</h2><p class=\"wp-block-paragraph\">The first sync sends every card. After that, clients use sync-collection (RFC 6578) and receive only the cards that changed, plus deletions for members who left the site or were blocked. A card counts as changed when its REV (last-changed time on that site) moves, which happens on changes to tracked user meta, email, display name, BuddyPress profile fields, the avatar, group membership, or a group&#8217;s name or status. Removals are remembered for 90 days; a client whose sync token is older than that is asked to start again with a full sync.</p><p class=\"wp-block-paragraph\">ETags, the collection CTag and sync tokens include a hash of which hidden groups the syncing user can see, and the plugin version, so a change in either refreshes that user&#8217;s cards.</p><h2 class=\"wp-block-heading\">Architecture</h2><ul class=\"wp-block-list\"><li><code>LH_Vcard_Carddav_Handler</code> &#8211; the protocol: a rewrite endpoint dispatched on <code>parse_request</code>, speaking WebDAV XML (PROPFIND, REPORT, GET, HEAD, OPTIONS). Not a REST route: the REST server only speaks JSON and runs every <code>determine_current_user</code> filter.</li><li><code>LH_Vcard_Carddav_Auth</code> &#8211; HTTP Basic Auth checked with <code>wp_authenticate_application_password()</code> directly, so other authentication filters (IndieAuth, SSO) take no part.</li><li><code>LH_Vcard_Carddav_Address_Book</code> &#8211; membership, revisions, ETags, CTag, sync tokens and changes.</li><li><code>LH_Vcard_Change_Tracker</code> &#8211; records each card&#8217;s REV per site and keeps removal tombstones (option <code>lh_vcard-carddav_tombstones</code>). Writes name their site explicitly instead of switching blogs.</li></ul><p class=\"wp-block-paragraph\">Download tokens now carry the viewer as well: <code>{expiry}.{viewer_id}.{hmac}</code>. Tokens from before 1.10.0 (<code>{expiry}.{hmac}</code>) are still accepted until they expire, as a viewer who sees no hidden groups.</p>"^^rdf:XMLLiteral ;
  sioc:content "Part of: LH VcardSince 1.10.0 each site&#8217;s members are also available as a read-only CardDAV address book, so staff can sync the whole club into their phone or desktop contacts instead of downloading cards. It replaced the separate LH CardDAV Server plugin, which was retired. A synced card is built by the same code as a downloaded one, so both always carry the same data.Setting it upYou need the capability that shows vCard links (publish_posts by default) and an application password (Users → Profile → Application Passwords). Your normal account password is not accepted.iPhone: Settings → Apps → Contacts → Contacts Accounts → Add Account → Other → Add CardDAV Account. Server is the site&#8217;s domain (e.g. princesparktouch.com), then your username and the application password.Android (DAVx5): Login with URL and user name, using https:// plus the site&#8217;s domain.Thunderbird: New CardDAV address book, using https:// plus the site&#8217;s domain.Apps find the address book on their own through /.well-known/carddav. If one does not, give it the full address: the site&#8217;s domain followed by /carddav/.What is in itEvery member of the site, except members blocked on it (LH Buddypress Block Members).Teams are the BuddyPress groups the person syncing can see: public and private groups always, hidden groups only for their own members and BuddyPress moderators. Downloads follow the same rule for whoever generated the link.It is read-only. Contacts apps cannot edit or delete cards; the site is the only place to change member details.How syncing worksThe first sync sends every card. After that, clients use sync-collection (RFC 6578) and receive only the cards that changed, plus deletions for members who left the site or were blocked. A card counts as changed when its REV (last-changed time on that site) moves, which happens on changes to tracked user meta, email, display name, BuddyPress profile fields, the avatar, group membership, or a group&#8217;s name or status. Removals are remembered for 90 days; a client whose sync token is older than that is asked to start again with a full sync.ETags, the collection CTag and sync tokens include a hash of which hidden groups the syncing user can see, and the plugin version, so a change in either refreshes that user&#8217;s cards.ArchitectureLH_Vcard_Carddav_Handler &#8211; the protocol: a rewrite endpoint dispatched on parse_request, speaking WebDAV XML (PROPFIND, REPORT, GET, HEAD, OPTIONS). Not a REST route: the REST server only speaks JSON and runs every determine_current_user filter.LH_Vcard_Carddav_Auth &#8211; HTTP Basic Auth checked with wp_authenticate_application_password() directly, so other authentication filters (IndieAuth, SSO) take no part.LH_Vcard_Carddav_Address_Book &#8211; membership, revisions, ETags, CTag, sync tokens and changes.LH_Vcard_Change_Tracker &#8211; records each card&#8217;s REV per site and keeps removal tombstones (option lh_vcard-carddav_tombstones). Writes name their site explicitly instead of switching blogs.Download tokens now carry the viewer as well: {expiry}.{viewer_id}.{hmac}. Tokens from before 1.10.0 ({expiry}.{hmac}) are still accepted until they expire, as a viewer who sees no hidden groups." ;
  sioc:topic <https://lhero.org/?taxonomy=author&term=cap-1> .

<https://lhero.org/author/1/#account> rdfs:seeAlso <https://lhero.org/author/1/?feed=lhrdf&format=turtle> .
<https://lhero.org/?taxonomy=author&term=cap-1> rdfs:seeAlso <https://lhero.org/?taxonomy=author&term=cap-1&feed=lhrdf&format=turtle> .
