Helping Organisations get organised!

Changelog

  • 1.11.0: The CardDAV address book now runs through the WordPress REST API, at /wp-json/lh-vcard/v1/carddav/, so every request a contacts app makes appears in REST request logs (such as LH REST API Logger’s) with its method, path, status and a short summary of the response. Cards themselves are not logged. /.well-known/carddav points to the new address, and the old /carddav/ address redirects to it. Authentication, cards, sync and permissions are unchanged.
  • 1.10.2: CardDAV test build: super admins’ contacts apps are now told the address book is fully writable (write, write-content and bind), so contacts added to it are actually uploaded. Every new contact is still refused and recorded; nothing is created or stored, and other users still see a read-only address book.
  • 1.10.1: Test build for adding contacts from a phone. Super admins (users with manage_network_options, filterable via lh_vcard_carddav_add_capability) are now offered adding on the CardDAV address book, so a contacts app lets them save a new contact into the site’s list. Every new contact is still refused: nothing is created, stored or deleted, and each refusal is recorded (the last 50, in the lh_vcard-carddav_refused_cards option) so it is possible to see how a contacts app copes and how often it retries. Edits to members’ cards are refused as before. Everyone else still sees a read-only list.
  • 1.10.0: Adds a read-only CardDAV address book, folded in from the retired LH CardDAV Server plugin, so staff can sync the site’s members into iPhone Contacts, DAVx5 or Thunderbird instead of downloading cards. It lives at /carddav/ (with /.well-known/carddav redirecting there) and serves the same cards as the downloads. Contacts apps sign in with the member’s username and an application password; the account password is not accepted. The address book is the site’s members, less anyone blocked on the site, and is open to the same users who can see vCard links (publish_posts by default, via lh_vcard_return_view_vcard_capability). Sync uses sync-collection, so after the first sync a client only receives cards that changed and is told to delete members who left the site or were blocked. Writes from clients are refused; the address book advertises itself as read-only. Teams on a card now follow BuddyPress’s own visibility rule for whoever the card is for: public and private groups always appear, hidden groups only for a viewer who belongs to that group or can moderate BuddyPress. This applies to downloads too, replacing 1.8.1’s every-group rule; a download link records who generated it. Links issued before this release keep working until they expire and show no hidden groups. A card’s last-changed time (its REV) now also moves when a member’s email, display name, BuddyPress profile fields, avatar or group memberships change, or when one of their groups is renamed or changes status. Fixed: new registrations got no REV and did not appear in Latest Vcards until they edited their name, and changing a tracked field could leave the rest of the request on the wrong site of the network. The lh_vcard_add_data filter now receives the viewer’s user ID as a third argument.
  • 1.9.0: LH Vcard now adds the vcard_url to LH Profile Page’s search-users MCP results itself, through search-users’ extension filters (LH Profile Page 3.9.0+), instead of LH Profile Page calling into LH Vcard. The link is unchanged: a signed, expiring token rather than a nonce, so it works for whoever opens it. It is now only added when the caller can view vCards (the lh_vcard_return_view_vcard_capability capability, publish_posts by default). The new class is LH_Vcard_Profile_Search. LH_Vcard_plugin::return_signed_vcard_download_url() stays for now, for LH Profile Page versions that still call it, and will be removed in a later release.
  • 1.8.1: Teams in vCards now include every BuddyPress group the member belongs to, including private and hidden groups, not only public ones. Each group is still written as a vCard category and as a labelled link to its group page.
  • 1.8.0: Improves the contact cards and brings the plugin up to current LocalHero standards. Teams: a member’s public BuddyPress groups now appear as proper vCard categories (shown as labels by Android and Google Contacts) and as one labelled link per team back to the team page, which iPhone shows as a tappable row named after the team. Hidden and private groups are no longer included in cards. The organisation field is now the club (site name) instead of the joined list of groups. Photos: the contact photo is now 256px instead of 55px (filterable via lh_vcard_return_photo_size), members with no uploaded BuddyPress avatar get no photo instead of the generic silhouette, and the photo URL now comes from get_avatar_url() rather than parsing avatar HTML, fixing a fallback that could return avatar markup as a URL. Each member now has a stable UID and a REV timestamp from the existing last-updated tracking, so re-importing an updated card can update the existing contact rather than duplicate it. The full name falls back to the display name when first and last name are empty, N is always present as vCard 3.0 requires, and the note now decodes all HTML entities rather than only the curly apostrophe, and is included even without BuddyPress. The Latest Vcards dashboard widget and shortcode now show an avatar image instead of a bare URL. Standards: removed the class_exists guard around the main plugin class, added plugin_version() reading the header, added the lh_vcard_init_plugin gate, added Requires at least and Requires PHP headers and a proper description, removed the closing PHP tag, and the add-data filter name is now derived from the plugin namespace (same lh_vcard_add_data name, so lh-profile-page is unaffected).
  • 1.7.1: Fixes vCards failing to save on iPhone. The contact photo was base64-encoded twice (sabre/vobject already encodes PHOTO values with ENCODING=b), so iOS could preview the card but showed a grey screen and could not save, share or forward it. The photo is now passed as raw bytes, its type is detected from the image itself rather than the URL extension, and a fetched photo that is not a valid image is left out instead of producing a broken card. The download now uses the standard text/vcard content type, is served inline so iOS offers Add to Contacts directly, and is sent with no-cache headers (including LiteSpeed no-cache) so personal contact details behind a signed link are no longer publicly cacheable. The filename is now quoted in Content-Disposition.
  • 1.07: Version bump 1.06 -> 1.07: a stray Composer-internal error_log file (benign, no sensitive content) got accidentally committed in the initial GitHub push; removed it and added .gitignore to prevent recurrence. No functional code change – version bump only, required to push the corrected repo state (push-plugin refuses to re-tag an already-pushed version).
  • 1.06: Sixth and final step of the class-per-concern refactor: LH_Vcard_plugin shrinks from ~1000 lines to a thin bootstrap (identity methods, plugin_init() hook wiring that now delegates to the five new classes, activation/deactivation, cron setup, singleton). Every extracted method’s logic is unchanged – only which class it lives on and, for the previously-instance methods moved to static classes, how it’s hooked (array(‘ClassName’,’method’) instead of array($this,’method’)). return_signed_vcard_download_url() stays here as a one-line proxy to LH_Vcard_Signed_Link’s method of the same name, since lh-profile-page’s search-users MCP ability calls that exact class/method directly – a confirmed external caller, not a hypothetical one. Version bump 1.05 -> 1.06.
  • 1.05: Cleanup pass on remaining plugin-check flags: (1) deleted curpageurl(), confirmed dead code with zero call sites; (2) added License/License URI to plugin header, clearing plugin_header_no_license; (3) escaped output at every remaining unescaped echo site (esc_url() on hrefs, esc_html__()/esc_html_e() on translated text, absint()/esc_attr() on IDs) across maybe_ad_vcard_link, bp_member_maybe_ad_vcard_link, bp_group_maybe_ad_vcard_link, add_content_to_report, add_link_for_bbpress, add_checkin_headers, and return_latest_updated_vcards_output; (4) left the two genuine false positives alone with an explanatory phpcs:ignore comment – the raw vCard file stream in stream_signed_vcard() and the already-escaped-at-source echo in do_lastest_vcards_widget(). Version bump 1.04 -> 1.05.
  • 1.04: Replace the unattributed, unmaintained bundled includes/wp-gvc-cf-vcard.class.php library with sabre/vobject (Packagist, actively maintained, standards-compliant). New private methods build_vcard_text()/fetch_photo_bytes()/guess_photo_type() replace the WP_gvc_vcard instantiation in stream_signed_vcard() – the only remaining call site after 1.03’s cleanup. Data contract into this (the $add array shape from add_to_vcard_data()/lh_vcard_add_data filter) is unchanged. Forces vCard 3.0 output. Fixes two latent bugs from the old library: a malformed 8-component ADR line, and missing RFC-required line-folding on long PHOTO data. Also swaps file_get_contents()->wp_remote_get() and parse_url()->wp_parse_url(). Version bump 1.03 -> 1.04.
  • 1.03: Every vCard download link now uses the signed download link from 1.02: user row actions, BuddyPress member and group links, group reports, the dashboard widget and bbPress reply links. The old admin-ajax download and its helper methods have been removed. Signed links now last 24 hours by default instead of 15 minutes, since they now serve long-lived pages such as the dashboard widget and reports.
  • 1.02: Adds signed vCard download links: an HMAC token that does not depend on who is logged in, served by a new REST route, GET /wp-json/lh-vcard/v1/download, so a link works for whoever opens it. First used for the vcard_url field of LH Profile Page’s search-users MCP ability; the other download links still used the old admin-ajax path in this release.
  • 1.01: Replaced bp_core_get_user_domain(), deprecated since BuddyPress 12.0, with bp_members_get_user_url(). When BuddyPress is not active the profile link falls back to the user’s edit link.
  • 1.00: Initial release. Exports user profiles as vCard files through admin-ajax, for logged-in users with the publish_posts capability. Adds vCard links to the user list, BuddyPress member profiles and groups, a group reports column, a dashboard widget of recently updated profiles, and a front-end shortcode for the same list.

If you like this plugin please consider making a donation to further development