Dieses Plugin ist eine klassische adm_plugins-Variante für Admidio 5.0.x ohne Abhängigkeit vom neuen Plugin-Manager-Stack.
index.php– Infoseite mit Konfigurationsstatusapi/api.php– JSON-API für Benutzer, Felder, Rollen, Kategorien, Arbeitsdienste und Mitgliedsart-Wechsel (via.htaccess)classes/Service/MembershipTypeService.php– Mitgliedsart-Wechsel überAdmHistory\MembershipApiclasses/Service/WorkHoursService.php– Arbeitsdienst-Stunden über das Plugin Mitgliedsbeitrag (WorkHoursApi)classes/Service/ApiUser.php– setzt den technischen API-Benutzer als angemeldeten Benutzerbootstrap-admidio.php– Bootstrap für klassische Admidio-Strukturenbootstrap-plugin.php– lokaler PSR-4-Autoloader
- Ordner
WpUserSyncnachadm_plugins/kopieren. - Konfiguration in
adm_my_files/config.phpergänzen (siehe Plugin-Infoseite in Admidio). - Ein langes gemeinsames Secret (
$plg_wpusersync_api_secret) setzen.
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule ^adm_plugins/wpusersync/api/v1/(.*)$ /adm_plugins/wpusersync/api/api.php [QSA,L]
</IfModule>
$plg_wpusersync_enabled = true;
$plg_wpusersync_require_https = true;
$plg_wpusersync_assign_default_roles = true;
$plg_wpusersync_api_secret = 'mein-langes-zufaelliges-shared-secret';
$plg_wpusersync_nonce_max_age = 300;
// API-Benutzer für alle Änderungen (Pflicht für POST/DELETE, siehe unten)
$plg_wpusersync_api_user_uuid = '00000000-0000-0000-0000-000000000000';
// optional, Standard: adm_plugins/adm-history
// $plg_wpusersync_admhistory_dir = __DIR__ . '/../adm_plugins/adm-history';
// optional, Standard: Ordner MembershipFee bzw. Mitgliedsbeitrag neben WpUserSync
// $plg_wpusersync_membershipfee_dir = __DIR__ . '/../adm_plugins/MembershipFee';Die API hat keine Admidio-Anmeldung. Nach erfolgreicher Signaturprüfung setzt api/api.php deshalb den Benutzer aus $plg_wpusersync_api_user_uuid als angemeldeten Benutzer ($gCurrentUser). Admidio trägt ihn bei allen Änderungen aus WordPress im Änderungsprotokoll ein.
- Schreibende Anfragen (POST, DELETE) werden ohne gültigen API-Benutzer mit
500undcode: api_user_not_configuredbzw.api_user_invalidabgelehnt. - Lesende Anfragen (GET) laufen mit dem API-Benutzer, falls konfiguriert, sonst als Gast.
- Rechte des API-Benutzers prüfen der Mitgliedsart-Wechsel (über adm-history) und der Arbeitsdienst (über das Plugin Mitgliedsbeitrag). Die übrigen Endpunkte schreiben weiterhin ohne Rechteprüfung.
Empfehlung: eigenen Admidio-Benutzer (z. B. „WordPress API“) ohne Login-Daten anlegen und ihm eine Rolle mit dem Recht „Rollen zuordnen“ für die betroffenen Rollen geben.
GET /adm_plugins/wpusersync/api/v1/core/users/{uuid}
X-Api-Client-Id: <feste_client_id>
X-Api-Timestamp: <unixzeit>
X-Api-Nonce: <zufaelliger_nonce>
X-Api-Body-Sha256: <sha256_hex_des_raw_json>
X-Api-Signature: <hmac_sha256_hex>
Content-Type: application/jsonSignatur-Basis (jeweils mit \n getrennt):
METHOD
PATH
CLIENT_ID
TIMESTAMP
NONCE
BODY_SHA256
URLs verwenden das Routing-Pattern via .htaccess:
/adm_plugins/wpusersync/api/v1/...
Alle Endpunkte erfordern HMAC-Request-Signing (siehe Authentifizierung oben).
Die Allowlist wird auf der Administratorseite /adm_plugins/wpusersync/index.php über getrennte Checkboxen für Lese- und Schreibzugriff gepflegt. Beim Speichern legt das Plugin adm_my_files/wpusersync-profile-fields.json an beziehungsweise aktualisiert diese Datei. Der PHP-Prozess muss Schreibrechte auf adm_my_files haben.
Eine fehlende Allowlist-Datei sperrt Profilfeld-Lese- und Schreibzugriffe standardmäßig (fail-closed). Für POST /core/users/new müssen FIRST_NAME, LAST_NAME und BIRTHDAY in der Schreib-Allowlist aktiviert sein. Benutzerlisten und Suchergebnisse geben diese Profilfelder nur zurück, wenn sie jeweils in der Lese-Allowlist stehen.
GET /core/users– Liste aller Benutzer (mit?limit=50&offset=0)GET /core/users/{uuid}– Benutzer anhand seiner UUID auslesenGET /core/search?firstName=...&lastName=...&birthday=...– Benutzer anhand Name und Geburtstag suchenPOST /core/users/new– Benutzer anlegen (erfordertfirstName,lastNameundbirthday)GET /core/roles– Rollen auflistenGET /core/categories– Kategorien auflistenGET /core/categories/{type}– Kategorien nach Typ auflisten
GET /core/users/{uuid}/fields– Profilfelder des Benutzers auslesenGET /core/users/{uuid}/fields/{name}– Einzelnes Profilfeld auslesenPOST /core/users/{uuid}/fields– Profilfelder setzen (mit{"data":{"FELDNAME":"Wert"}})POST /core/users/{uuid}/fields/{name}– Einzelnes Profilfeld setzen (mit{"data":"Wert"})
GET /core/users/{uuid}/memberships– Mitgliedschaften des Benutzers auslesenGET /core/users/{uuid}/memberships/{year}– Mitgliedschaften für ein Jahr auslesenPOST /core/users/{uuid}/memberships– Rollenmitgliedschaften zuweisen (mit{"roles":{"Rollenname":{"start_date":"YYYY-MM-DD","end_date":"YYYY-MM-DD"}}})POST /core/users/{uuid}/mitgliedschaftbfv– BFV-Mitgliedschaft und Beitragsrollen verwalten- Arbeitsdienst: siehe eigener Abschnitt unten.
Die Stunden stehen im Plugin Mitgliedsbeitrag (Tabelle adm_plugin_membershipfee_workhours, Seite „Arbeitsdienst erfassen“). WpUserSync ruft dessen Schnittstelle Plugins\MembershipFee\classes\Work\WorkHoursApi auf; alle Regeln stehen dort. Die frühere Tabelle adm_user_arbeitsdienst des alten Plugins „arbeitsdienst“ wird nicht mehr verwendet.
Voraussetzungen:
- Plugin Mitgliedsbeitrag ab der Version mit
classes/Work/WorkHoursApi.phpinadm_plugins/MembershipFee(oderMitgliedsbeitrag, oder$plg_wpusersync_membershipfee_dir). Fehlt es, antworten die Endpunkte mit501undcode: membershipfee_missing. - Zum Schreiben braucht der API-Benutzer die Zugriffsrolle des Beitragsplugins oder muss den Menüpunkt „Arbeitsdienst erfassen“ sehen dürfen (in der Menüverwaltung unter „Sichtbar für“ eintragen). Sonst
403,code: forbidden.
Endpunkte:
GET /core/users/{uuid}/arbeitsdienst– alle Jahre mit Einträgen und das aktuelle JahrGET /core/users/{uuid}/arbeitsdienst/{year}– ein LeistungsjahrPOST /core/users/{uuid}/arbeitsdienst– Eintrag anlegen oder (mitid) ändernPOST /core/users/{uuid}/arbeitsdienst/{year}– wie oben; das Datum muss im Jahr liegenDELETE /core/users/{uuid}/arbeitsdienst/{id}– Eintrag löschenPOST /core/users/{uuid}/arbeitsdienst/soll– Sollstunden setzen (Profilfeld „Sollstunden Arbeitsdienst“), Body{"target_hours": 10};nullleert das Feld. Antwort wie beim Lesen des aktuellen Jahres mitaction: "target_updated". Hinweis: „Sollstunden abgleichen“ in Admidio kann den Wert später wieder nach den Regeln setzen.
Anlegen (Datum, Stunden und Einsatz sind Pflicht; name wird wie activity akzeptiert):
{"data": {"date": "2026-04-18", "hours": 2.5, "activity": "Gewässerputzete", "comment": "Ufer Nord"},
"check_duplicates": true}Ändern (nur die geänderten Felder): {"data": {"id": 123, "hours": 4}}
Mit check_duplicates (alt: check_dublicates) wird ein Eintrag mit gleichem Datum, Einsatz und Stunden nicht doppelt angelegt; die Antwort hat dann action: "exists" und den vorhandenen Eintrag. Wiederholtes Senden aus WordPress ist damit unschädlich. Die id aus der Antwort sollte WordPress speichern, um später zu ändern oder zu löschen.
Antwort (lesen und schreiben):
{"status": "success", "action": "created",
"entry": {"id": 123, "date": "2026-04-18", "year": 2026, "hours": 2.5, "activity": "Gewässerputzete", "comment": "Ufer Nord", "created_at": "…", "changed_at": null},
"user_uuid": "…", "target_hours": 10,
"years": [{"year": 2026, "done_hours": 2.5, "missing_hours": 7.5, "locked": false, "entries": [ … ]}]}actiongibt es nur beim Schreiben:created,updated,exists,deleted.target_hoursist das Profilfeld „Sollstunden Arbeitsdienst“ (ein Wert, nicht je Jahr;null, wenn leer).missing_hoursrechnet wie die Jahresübersicht mit diesem Wert.locked: trueheißt: Das Jahr ist abgerechnet (Arbeitsdienst exportiert oder eingezogen). Schreiben und Löschen antworten dann mit409,code: year_locked; Korrekturen nur noch in Admidio.- Weitere Fehler:
404 user_not_found,404 not_found(Eintrag gehört nicht zum Mitglied),422 not_member_in_year(Mitglied im Leistungsjahr in keiner Rolle),422 validation_failed. - Beträge (Ersatzbeitrag) gibt die API nicht aus.
Voraussetzung: Das Plugin „Mitglieder-Historie“ liegt in adm_plugins/adm-history (oder in $plg_wpusersync_admhistory_dir). Erlaubte Wechsel, Pflicht- und optionale Beitragsrollen stehen ausschließlich in adm-history/mitgliedsarten.php und werden von AdmHistory\MembershipApi geprüft. Ein Wechsel gilt immer ab dem 1. Januar, nur für das aktuelle Jahr und das Folgejahr.
Geändert wird im Namen des API-Benutzers (siehe „API-Benutzer“). Für den Wechsel braucht er das Recht, Mitglieder aller Mitgliedsart-, gemeinsamen und Beitragsrollen zuzuordnen.
GET /core/mitgliedsarten– konfigurierte Mitgliedsarten mit Rollen, Pflicht-/optionalen Beitragsrollen und erlaubten ZielenGET /core/users/{uuid}/mitgliedsart– je Jahr (aktuell, Folgejahr): Mitgliedsart am 31.12., Zusatzbeiträge undoptions(bisherige Art plus erlaubte Ziele mit ihren optionalen Beitragsrollen) – geeignet, um in WordPress die Auswahl aufzubauenPOST /core/users/{uuid}/mitgliedsart– Mitgliedsart und Zusatzbeiträge setzen:year(Pflicht): aktuelles Jahr oder Folgejahrart(Pflicht): Kürzel oder Name, z. B."A"oder"Aktiv";""= Kündigungfee(optional): genau diese optionalen Beitragsrollen gelten danach im Jahr,[]entfernt alle. Fehltfee, bleiben bisherige Zusatzbeiträge, soweit sie zur neuen Mitgliedsart gehören.
{"year": 2027, "art": "A", "fee": ["Bootsbeitrag"]}Antwort: art, name, fees, operations (Anzahl Datenbankänderungen, 0 = nichts zu tun) und der neue Stand years wie beim GET. Fachliche Fehler (nicht erlaubter Wechsel, unpassender Zusatzbeitrag, fehlende Rechte) antworten mit 422 und code: membership_change_failed.
Schreibzugriffe verwenden JSON im Request-Body. Der Router unterstützt nur die oben aufgeführten HTTP-Methoden und Routen; nicht aufgeführte Routen antworten mit 404.
Benutzer auslesen:
curl -X GET https://example.org/adm_plugins/wpusersync/api/v1/core/users/00000000-0000-0000-0000-000000000000 \
-H "X-Api-Client-Id: wordpress-prod" \
-H "X-Api-Timestamp: $(date +%s)" \
-H "X-Api-Nonce: $(openssl rand -hex 16)" \
-H "X-Api-Body-Sha256: $(echo -n '' | sha256sum | cut -d' ' -f1)" \
-H "X-Api-Signature: <HMAC-SHA256>" \
-H "Content-Type: application/json"Custom-Field setzen:
PAYLOAD='{"data":"neuer-wert"}'
curl -X POST https://example.org/adm_plugins/wpusersync/api/v1/core/users/00000000-0000-0000-0000-000000000000/fields/mein_feld \
-H "X-Api-Client-Id: wordpress-prod" \
-H "X-Api-Timestamp: $(date +%s)" \
-H "X-Api-Nonce: $(openssl rand -hex 16)" \
-H "X-Api-Body-Sha256: $(echo -n "$PAYLOAD" | sha256sum | cut -d' ' -f1)" \
-H "X-Api-Signature: <HMAC-SHA256>" \
-H "Content-Type: application/json" \
-d "$PAYLOAD"