{"id":384359,"date":"2026-10-12T17:30:49","date_gmt":"2026-10-12T17:30:49","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/pcio-vis-with-foreninglet\/"},"modified":"2026-10-12T17:42:00","modified_gmt":"2026-10-12T17:42:00","slug":"pcio-vis-with-foreninglet","status":"publish","type":"plugin","link":"https:\/\/wordpress.org\/plugins\/pcio-vis-with-foreninglet\/","author":20981457,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"1.0.2","stable_tag":"1.0.2","tested":"7.1.3","requires":"6.2","requires_php":"8.1","requires_plugins":null,"header_name":"PCIO VIS With ForeningLet","header_author":"PCIO","header_description":"Imports ForeningLet members into PCIO VIS Member Event through a registered sync job.","assets_banners_color":"000000","last_updated":"2026-10-12 17:42:00","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"https:\/\/www.pcio.dk\/vis-plugins","header_author_uri":"https:\/\/www.pcio.dk","rating":0,"author_block_rating":0,"active_installs":0,"downloads":76,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"1.0.0":{"tag":"1.0.0","author":"pcio","date":"2026-10-12 17:30:22","revision":3742244},"1.0.1":{"tag":"1.0.1","author":"pcio","date":"2026-10-12 17:34:19","revision":3742252},"1.0.2":{"tag":"1.0.2","author":"pcio","date":"2026-10-12 17:42:00","revision":3742262}},"upgrade_notice":[],"ratings":[],"assets_icons":{"icon-128x128.png":{"filename":"icon-128x128.png","revision":3742237,"resolution":"128x128","location":"assets","locale":"","width":128,"height":128},"icon-256x256.png":{"filename":"icon-256x256.png","revision":3742237,"resolution":"256x256","location":"assets","locale":"","width":256,"height":256}},"assets_banners":{"banner-1544x500.png":{"filename":"banner-1544x500.png","revision":3742237,"resolution":"1544x500","location":"assets","locale":"","width":1544,"height":500},"banner-772x250.png":{"filename":"banner-772x250.png","revision":3742237,"resolution":"772x250","location":"assets","locale":"","width":772,"height":250}},"assets_blueprints":{},"all_blocks":[],"tagged_versions":["1.0.0","1.0.1","1.0.2"],"block_files":[],"assets_screenshots":{"screenshot-1.jpg":{"filename":"screenshot-1.jpg","revision":3742249,"resolution":"1","location":"assets","locale":"","width":2545,"height":1080}},"screenshots":{"1":"Url and credentials to access the API at ForeningLet is saved under WP Admin Vis ForeningLet"}},"plugin_section":[],"plugin_tags":[286247,1919,1932,1558],"plugin_category":[58],"plugin_contributors":[265152],"plugin_business_model":[],"class_list":["post-384359","plugin","type-plugin","status-publish","hentry","plugin_tags-foreninglet","plugin_tags-members","plugin_tags-membership","plugin_tags-sync","plugin_category-user-management","plugin_contributors-pcio","plugin_committers-pcio"],"banners":{"banner":"https:\/\/ps.w.org\/pcio-vis-with-foreninglet\/assets\/banner-772x250.png?rev=3742237","banner_2x":"https:\/\/ps.w.org\/pcio-vis-with-foreninglet\/assets\/banner-1544x500.png?rev=3742237","banner_rtl":false,"banner_2x_rtl":false},"icons":{"svg":false,"icon":"https:\/\/ps.w.org\/pcio-vis-with-foreninglet\/assets\/icon-128x128.png?rev=3742237","icon_2x":"https:\/\/ps.w.org\/pcio-vis-with-foreninglet\/assets\/icon-256x256.png?rev=3742237","generated":false},"screenshots":[{"src":"https:\/\/ps.w.org\/pcio-vis-with-foreninglet\/assets\/screenshot-1.jpg?rev=3742249","caption":"Url and credentials to access the API at ForeningLet is saved under WP Admin Vis ForeningLet"}],"raw_content":"<!--section=description-->\n<p>PCIO VIS With ForeningLet extends PCIO VIS Member Event with one member-import job.\nConfigure the connection under <strong>Vis &gt; ForeningLet &gt; Config<\/strong>. Manage the job,\nits schedule, manual runs and last result under <strong>Vis &gt; Sync Jobs<\/strong>.<\/p>\n\n<p>Every member returned by the ForeningLet member-list API is considered valid,\nregardless of balance. Duplicate member numbers are resolved by preferring the\nlower SaldoPaymentDeadline. Different member numbers remain separate even when\nthey share an email address.<\/p>\n\n<p>The importer creates or refreshes core member records using MemberNumber, FirstName,\nLastName, Email, Phone (or Mobile) and EnrollmentDate. It matches existing records by\nmember number first. Email is used only as a fallback when it identifies a single\nsource member and a single existing record; shared emails never merge people.\nDuplicate member numbers in the local database and conflicting account links\ncancel the sync before any changes.\nIt preserves local addresses, volunteer flags, leave dates and existing Vis roles.\nLegacy interest, balance and newsletter fields are not copied into unrelated core fields.<\/p>\n\n<p>New members receive a linked WordPress subscriber account with a generated password\nand a username containing their member number (for example, foreninglet_677).\nExisting unlinked accounts are matched by email only when that email identifies a\nsingle source member and a single unlinked WordPress account.\nShared-email members without existing links get separate accounts with the real\nshared email address. The importer temporarily allows that email only during\naccount creation; it does not disable WordPress email checks elsewhere.\nMembers sharing an email must log in and request password resets by username,\nsince email-based lookup cannot distinguish their accounts. Anyone with access to\nthat shared mailbox can receive password resets for those accounts.\nNew accounts receive vis_member. Existing accounts keep their login, password,\nprofile and WordPress role.\nExisting member links are retained when the ForeningLet contact email changes.\nNo welcome emails are sent.<\/p>\n\n<p>After a successful import, vis_member is removed from WordPress accounts that are\nnot represented in the returned list, including accounts not linked to a Vis record.\nWordPress administrators and multisite super administrators are never changed,\nincluding their linked member records. Accounts with vis_volunteer never lose vis_member.\nNo member records or WordPress accounts are deleted.<\/p>\n\n<p>Failed requests, unexpected payloads, malformed member records, ambiguous matches\nand import failures prevent revocation. A successful empty JSON array represents\nan empty membership list and revokes all unprotected memberships.<\/p>\n\n<p>The job is installed disabled with a 24-hour frequency, following the core sync-job\nconvention. It makes no API calls until explicitly run or enabled after configuration.\nWordPress cron requires site traffic or an external scheduler.<\/p>\n\n<p>Do not enable another membership sync as an alternative source of truth at the same\ntime: the core Sync WP Users job can re-grant membership to retained former members,\nand other integrations may apply different removal rules.<\/p>\n\n<p>Deactivation disables the registry job and clears its scheduled event, retaining\nsettings and job history. Re-enable the job after reactivation if required.\nDeletion removes this extension's options and its job when the core is active.\nImported records, accounts and membership capabilities are retained.<\/p>\n\n<h3>External services<\/h3>\n\n<p>This plugin connects to the ForeningLet membership API, operated by ForeningLet,\nonly after an administrator configures API credentials and runs or enables the job.\nNo external requests are made during ordinary browsing or while displaying settings.<\/p>\n\n<ul>\n<li><strong>When:<\/strong> each manual run or scheduled execution of ForeningLet member sync.<\/li>\n<li><strong>Where:<\/strong> https:\/\/foreninglet.dk\/api\/members?version=1 over HTTPS.<\/li>\n<li><strong>What is sent:<\/strong> the configured API username and password in an HTTP Basic\nauthentication header, the API version query and normal HTTP request metadata\n(including the server IP address). Local member records are not uploaded.<\/li>\n<li><strong>What is received:<\/strong> the account's member list, including member identifiers,\nnames, email addresses, phone numbers, enrollment dates and balances. Supported\ncontact fields are stored locally; balances are used only for deduplication.<\/li>\n<\/ul>\n\n<p>Ensure you have authority to retrieve these personal data and that your privacy\npolicy covers their processing and local storage. The association is responsible\nfor its ForeningLet agreement and any required data processing agreement.<\/p>\n\n<ul>\n<li>Service information and contractual terms: https:\/\/web.foreninglet.dk\/<\/li>\n<li>Privacy policy: https:\/\/web.foreninglet.dk\/privatlivspolitik\/<\/li>\n<li>Data protection information: https:\/\/web.foreninglet.dk\/gdpr\/<\/li>\n<\/ul>\n\n<p>ForeningLet is a trademark of its respective owner. This plugin is an independent\nPCIO integration and is not affiliated with, sponsored by or endorsed by ForeningLet.<\/p>\n\n<h3>Development<\/h3>\n\n<p>Standalone regression tests live outside the distributable plugin at\nwww\/pcio-vis-with-foreninglet\/sync.test.php in the source repository.\nRun them with PHP from the repository root. The harness is CLI-only and mocks\nWordPress APIs; it is not part of the WordPress.org plugin package.<\/p>\n\n<p>The repository's www\/pcio-vis-with-foreninglet\/phpcs.xml.dist enables the complete WordPress coding standard,\nenforces the pcio_vis global prefix and checks the pcio-vis-with-foreninglet text\ndomain. With WPCS installed, run phpcs --standard=www\/pcio-vis-with-foreninglet\/phpcs.xml.dist\nfrom the repository root. This development-only configuration is not included in\nthe deployed plugin or WordPress.org package.<\/p>\n\n<!--section=installation-->\n<ol>\n<li>Install and activate PCIO VIS Member Event.<\/li>\n<li>Upload pcio-vis-with-foreninglet to \/wp-content\/plugins\/ and activate it.<\/li>\n<li>Open Vis &gt; ForeningLet and enter the host and API credentials as username:password.<\/li>\n<li>Save the settings. Saving credentials authorizes requests when the job is run.<\/li>\n<li>Under Vis &gt; Sync Jobs, run ForeningLet member sync manually and inspect the result.<\/li>\n<li>Enable that job for automatic daily synchronization, or choose another frequency.<\/li>\n<\/ol>\n\n<!--section=faq-->\n<dl>\n<dt id=\"what%20is%20the%20host%20setting%3F\"><h3>What is the host setting?<\/h3><\/dt>\n<dd><p>The complete member-list URL: https:\/\/foreninglet.dk\/api\/members?version=1.\nOnly this HTTPS ForeningLet endpoint is accepted; redirects and filtered or\npaginated URLs are rejected to protect credentials and membership reconciliation.<\/p><\/dd>\n<dt id=\"how%20are%20api%20credentials%20stored%3F\"><h3>How are API credentials stored?<\/h3><\/dt>\n<dd><p>As a non-autoloaded WordPress option, accessible through the settings page only to\nusers with manage_options. The password is never displayed or included in sync results.\nCredentials are not encrypted at rest; protect database access and backups.\nLeave the password field blank to keep it, or select Remove saved credentials to clear it.<\/p><\/dd>\n<dt id=\"what%20if%20someone%20has%20no%20email%20address%3F\"><h3>What if someone has no email address?<\/h3><\/dt>\n<dd><p>They are skipped without stopping other imports, and the final result includes\n\"no email:1\" (or the actual number skipped after deduplicating member numbers).\nNo new record or account is created for them. If their member number already has\na linked account, its existing contact data and membership are preserved.<\/p><\/dd>\n<dt id=\"what%20if%20someone%20has%20an%20invalid%20email%20address%20or%20member%20number%3F\"><h3>What if someone has an invalid email address or member number?<\/h3><\/dt>\n<dd><p>A non-empty invalid email address or invalid member number still rejects the\nentire import before any membership changes. Correct the source data and retry.\nThe sync result identifies the first failing record by its one-based position in\nthe API array and member number, followed by the exact field and validation\nrequirement. Names, email addresses, passwords and other raw field values are\nnever included in these diagnostics. No memberships are changed for an invalid list.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>1.0.2<\/h4>\n\n<ul>\n<li>Screenshot updated<\/li>\n<\/ul>\n\n<h4>1.0.0<\/h4>\n\n<ul>\n<li>Skip and count members without email instead of aborting the import.<\/li>\n<li>Keep shared-email members separate with member-number usernames and stable account links.<\/li>\n<li>Initial member API integration, protected capability reconciliation and Vis configuration.<\/li>\n<\/ul>","raw_excerpt":"Imports ForeningLet members into PCIO VIS Member Event using a configurable cron sync job.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/384359","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=384359"}],"author":[{"embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/pcio"}],"wp:attachment":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=384359"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=384359"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=384359"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=384359"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=384359"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=384359"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}