Keep profile photos and fields in line with Microsoft 365 on every run
Some checks are pending
CI / PHP lint (7.4) (pull_request) Waiting to run
CI / PHP lint (8.0) (pull_request) Waiting to run
CI / PHP lint (8.1) (pull_request) Waiting to run
CI / PHP lint (8.2) (pull_request) Waiting to run
CI / PHP lint (8.3) (pull_request) Waiting to run
CI / PHP lint (8.4) (pull_request) Waiting to run
CI / WordPress Coding Standards (pull_request) Waiting to run
CI / WordPress.org Plugin Check (pull_request) Waiting to run

- Photo versions are compared on every sync run via Graph $batch
  (20 users per request); only changed photos are downloaded, the old
  file is deleted and the avatar URL changes. Photos deleted in
  Microsoft 365 are deleted in WordPress. Graph errors never delete a
  photo. Download limit per run (500) with deferral to the next run.
- Switching the photo sync off removes all stored photos; deselected
  m365_* profile fields are removed from the profiles.
- A user's photo is deleted together with the user (delete_user hook).
- Dry run reports photo changes without downloading.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Friederich Loheide 2026-09-23 16:40:45 +00:00
parent 4edf20bc45
commit 9f77e9027f
11 changed files with 589 additions and 339 deletions

View file

@ -124,7 +124,7 @@ msgstr "Du hast ungespeicherte Änderungen. Der Sync verwendet die gespeicherten
msgid "Move up"
msgstr "Nach oben"
#: includes/class-m365-login-admin.php:261 includes/class-m365-login-admin.php:300 includes/class-m365-login-admin.php:326 includes/class-m365-login-admin.php:359 includes/class-m365-login-admin.php:514 includes/class-m365-login-sync.php:1495
#: includes/class-m365-login-admin.php:261 includes/class-m365-login-admin.php:300 includes/class-m365-login-admin.php:326 includes/class-m365-login-admin.php:359 includes/class-m365-login-admin.php:514 includes/class-m365-login-sync.php:1611
msgid "You are not allowed to do this."
msgstr "Dafür fehlt die Berechtigung."
@ -428,8 +428,8 @@ msgid "Selected Microsoft 365 attributes are copied into the WordPress profile o
msgstr "Ausgewählte Microsoft-365-Attribute werden bei jedem Sync ins WordPress-Profil übernommen (Microsoft 365 hat Vorrang). Namen landen in den normalen Profilfeldern, alles andere in Benutzer-Metadaten mit dem Präfix „m365_“ nutzbar für Themes und andere Plugins und wird auf der Profilseite angezeigt."
#: includes/class-m365-login-admin.php:643
msgid "Profile photos are stored in wp-content/uploads/m365-login-avatars/ and replace the Gravatar. They are checked about once a day per user."
msgstr "Profilbilder werden in wp-content/uploads/m365-login-avatars/ gespeichert und ersetzen den Gravatar. Sie werden etwa einmal täglich pro Benutzer geprüft."
msgid "Profile photos are stored in wp-content/uploads/m365-login-avatars/ and replace the Gravatar. They are compared on every run: changed photos are downloaded again, photos deleted in Microsoft 365 are deleted in WordPress too. Fields and photos you deselect here are removed from the profiles on the next run (first and last name and display name stay)."
msgstr "Profilbilder werden in wp-content/uploads/m365-login-avatars/ gespeichert und ersetzen den Gravatar. Sie werden bei jedem Lauf abgeglichen: Geänderte Bilder werden neu geladen, in Microsoft 365 gelöschte Bilder auch in WordPress gelöscht. Felder und Bilder, die du hier abwählst, werden beim nächsten Lauf aus den Profilen entfernt (Vor-, Nach- und Anzeigename bleiben)."
#: includes/class-m365-login-admin.php:647
msgid "Disabled and deleted Microsoft 365 accounts"
@ -1119,7 +1119,7 @@ msgstr "Zu viele Versuche. Bitte 15 Minuten warten."
msgid "Too many sign-in attempts from your connection. Please wait a few minutes and try again."
msgstr "Zu viele Anmeldeversuche von dieser Verbindung. Bitte ein paar Minuten warten und erneut versuchen."
#: includes/class-m365-login-auth.php:864 includes/class-m365-login-sync.php:1404
#: includes/class-m365-login-auth.php:864 includes/class-m365-login-sync.php:1520
msgid "This account has been deactivated."
msgstr "Dieses Konto wurde deaktiviert."
@ -1175,15 +1175,15 @@ msgstr "Das Zertifikat gehört nicht zu diesem privaten Schlüssel."
msgid "The certificate has already expired."
msgstr "Das Zertifikat ist bereits abgelaufen."
#: includes/class-m365-login-graph.php:375
#: includes/class-m365-login-graph.php:434
msgid "Group"
msgstr "Gruppe"
#: includes/class-m365-login-graph.php:377
#: includes/class-m365-login-graph.php:436
msgid "Security group"
msgstr "Sicherheitsgruppe"
#: includes/class-m365-login-graph.php:379
#: includes/class-m365-login-graph.php:438
msgid "Microsoft 365 group"
msgstr "Microsoft 365-Gruppe"
@ -1235,293 +1235,312 @@ msgstr "Die eigene Login-Seite muss eine URL dieser Website sein."
msgid "User sync: \"Delete\" needs a user who receives the posts of deleted accounts. Until one is selected, accounts are deactivated instead."
msgstr "Benutzer-Sync: „Löschen“ braucht einen Benutzer, der die Beiträge gelöschter Konten übernimmt. Bis einer ausgewählt ist, werden Konten stattdessen deaktiviert."
#: includes/class-m365-login-sync.php:109
#: includes/class-m365-login-sync.php:110
msgid "Display name"
msgstr "Anzeigename"
#: includes/class-m365-login-sync.php:113
#: includes/class-m365-login-sync.php:114
msgid "First name"
msgstr "Vorname"
#: includes/class-m365-login-sync.php:117
#: includes/class-m365-login-sync.php:118
msgid "Last name"
msgstr "Nachname"
#: includes/class-m365-login-sync.php:121
#: includes/class-m365-login-sync.php:122
msgid "Profile photo (used as avatar)"
msgstr "Profilbild (als Avatar)"
#: includes/class-m365-login-sync.php:125
#: includes/class-m365-login-sync.php:126
msgid "Job title"
msgstr "Position"
#: includes/class-m365-login-sync.php:129
#: includes/class-m365-login-sync.php:130
msgid "Department"
msgstr "Abteilung"
#: includes/class-m365-login-sync.php:133
#: includes/class-m365-login-sync.php:134
msgid "Company"
msgstr "Firma"
#: includes/class-m365-login-sync.php:137
#: includes/class-m365-login-sync.php:138
msgid "Office"
msgstr "Büro"
#: includes/class-m365-login-sync.php:141
#: includes/class-m365-login-sync.php:142
msgid "Employee ID"
msgstr "Personalnummer"
#: includes/class-m365-login-sync.php:145
#: includes/class-m365-login-sync.php:146
msgid "Business phone"
msgstr "Telefon (geschäftlich)"
#: includes/class-m365-login-sync.php:149
#: includes/class-m365-login-sync.php:150
msgid "Mobile phone"
msgstr "Mobiltelefon"
#: includes/class-m365-login-sync.php:153
#: includes/class-m365-login-sync.php:154
msgid "Street address"
msgstr "Straße"
#: includes/class-m365-login-sync.php:157
#: includes/class-m365-login-sync.php:158
msgid "Postal code"
msgstr "Postleitzahl"
#: includes/class-m365-login-sync.php:161
#: includes/class-m365-login-sync.php:162
msgid "City"
msgstr "Ort"
#: includes/class-m365-login-sync.php:165
#: includes/class-m365-login-sync.php:166
msgid "State / province"
msgstr "Bundesland / Region"
#: includes/class-m365-login-sync.php:169
#: includes/class-m365-login-sync.php:170
msgid "Country"
msgstr "Land"
#: includes/class-m365-login-sync.php:173
#: includes/class-m365-login-sync.php:174
msgid "Language (sets the admin language if installed)"
msgstr "Sprache (setzt die Backend-Sprache, falls installiert)"
#: includes/class-m365-login-sync.php:308
#: includes/class-m365-login-sync.php:309
msgid "Another sync is still running. Please try again in a few minutes."
msgstr "Ein anderer Sync läuft noch. Bitte versuche es in ein paar Minuten erneut."
#: includes/class-m365-login-sync.php:365
#: includes/class-m365-login-sync.php:366
msgid "The connection to Microsoft Entra ID is not configured yet."
msgstr "Die Verbindung zu Microsoft Entra ID ist noch nicht eingerichtet."
#: includes/class-m365-login-sync.php:369
#: includes/class-m365-login-sync.php:370
msgid "The user sync needs a pinned tenant ID (GUID) on the Connection tab."
msgstr "Der Benutzer-Sync braucht eine feste Tenant-ID (GUID) im Tab „Verbindung“."
#: includes/class-m365-login-sync.php:373
#: includes/class-m365-login-sync.php:374
msgid "The default role does not exist. Please check the sync settings."
msgstr "Die Standardrolle existiert nicht. Bitte prüfe die Sync-Einstellungen."
#. translators: %d: number of users
#: includes/class-m365-login-sync.php:385
#: includes/class-m365-login-sync.php:386
msgid "%d user read from Microsoft 365."
msgid_plural "%d users read from Microsoft 365."
msgstr[0] "%d Benutzer aus Microsoft 365 gelesen."
msgstr[1] "%d Benutzer aus Microsoft 365 gelesen."
#. translators: 1: number of accounts, 2: limit
#: includes/class-m365-login-sync.php:435
#: includes/class-m365-login-sync.php:443
msgid "Safety stop: %1$d accounts would be deactivated or deleted, more than the limit of %2$d per run. No account was deactivated or deleted. Check the sync groups and the tenant, then run the sync again (the limit can be changed with the m365_login_sync_deprovision_limit filter)."
msgstr "Sicherheitsstopp: %1$d Konten würden deaktiviert oder gelöscht, mehr als das Limit von %2$d pro Lauf. Es wurde kein Konto deaktiviert oder gelöscht. Prüfe die Sync-Gruppen und den Tenant und starte den Sync dann erneut (das Limit lässt sich mit dem Filter m365_login_sync_deprovision_limit ändern)."
#. translators: %s: user principal name
#: includes/class-m365-login-sync.php:559
#: includes/class-m365-login-sync.php:567
msgid "%s: no usable e-mail address, skipped."
msgstr "%s: keine verwendbare E-Mail-Adresse, übersprungen."
#. translators: %s: e-mail address
#: includes/class-m365-login-sync.php:566
#: includes/class-m365-login-sync.php:574
msgid "%s: e-mail domain is not on the allow-list, skipped."
msgstr "%s: E-Mail-Domain steht nicht auf der Liste erlaubter Domains, übersprungen."
#. translators: %s: e-mail address
#: includes/class-m365-login-sync.php:578
#: includes/class-m365-login-sync.php:586
msgid "%s: the WordPress account with this e-mail address is linked to a different Microsoft account, skipped."
msgstr "%s: Das WordPress-Konto mit dieser E-Mail-Adresse ist mit einem anderen Microsoft-Konto verknüpft, übersprungen."
#. translators: %s: e-mail address
#: includes/class-m365-login-sync.php:582
#: includes/class-m365-login-sync.php:590
msgid "%s: existing account linked."
msgstr "%s: bestehendes Konto verknüpft."
#: includes/class-m365-login-sync.php:596 includes/class-m365-login-sync.php:931 includes/class-m365-login-sync.php:1536
#: includes/class-m365-login-sync.php:604 includes/class-m365-login-sync.php:955 includes/class-m365-login-sync.php:1652
msgid "disabled in Microsoft 365"
msgstr "in Microsoft 365 deaktiviert"
#. translators: %s: e-mail address
#: includes/class-m365-login-sync.php:607
#: includes/class-m365-login-sync.php:615
msgid "%s: added to this site."
msgstr "%s: zu dieser Website hinzugefügt."
#. translators: %s: e-mail address
#: includes/class-m365-login-sync.php:616
#: includes/class-m365-login-sync.php:624
msgid "%s: reactivated (active in Microsoft 365 again)."
msgstr "%s: reaktiviert (in Microsoft 365 wieder aktiv)."
#. translators: 1: e-mail address, 2: list of changed fields
#: includes/class-m365-login-sync.php:627
#: includes/class-m365-login-sync.php:635
msgid "%1$s: updated (%2$s)."
msgstr "%1$s: aktualisiert (%2$s)."
#. translators: 1: e-mail address, 2: role names
#: includes/class-m365-login-sync.php:653
#: includes/class-m365-login-sync.php:661
msgid "%1$s: account created (%2$s)."
msgstr "%1$s: Konto angelegt (%2$s)."
#. translators: 1: e-mail address, 2: error message
#: includes/class-m365-login-sync.php:680
#: includes/class-m365-login-sync.php:688
msgid "%1$s: account could not be created: %2$s"
msgstr "%1$s: Konto konnte nicht angelegt werden: %2$s"
#. translators: %s: e-mail address
#: includes/class-m365-login-sync.php:738
#: includes/class-m365-login-sync.php:746
msgid "%s: e-mail address is used by another WordPress account and was not changed."
msgstr "%s: Die E-Mail-Adresse gehört bereits einem anderen WordPress-Konto und wurde nicht geändert."
#. translators: %s: e-mail address
#: includes/class-m365-login-sync.php:741
#: includes/class-m365-login-sync.php:749
msgid "e-mail"
msgstr "E-Mail"
#. translators: %s: profile field
#: includes/class-m365-login-sync.php:799
msgid "%s removed"
msgstr "%s entfernt"
#. translators: 1: e-mail address, 2: error message
#: includes/class-m365-login-sync.php:785
#: includes/class-m365-login-sync.php:809
msgid "%1$s: profile could not be updated: %2$s"
msgstr "%1$s: Profil konnte nicht aktualisiert werden: %2$s"
#. translators: %s: role names
#: includes/class-m365-login-sync.php:891
#: includes/class-m365-login-sync.php:915
msgid "roles: %s"
msgstr "Rollen: %s"
#: includes/class-m365-login-sync.php:926 includes/class-m365-login-sync.php:1537
#: includes/class-m365-login-sync.php:950 includes/class-m365-login-sync.php:1653
msgid "deleted in Microsoft 365"
msgstr "in Microsoft 365 gelöscht"
#: includes/class-m365-login-sync.php:934 includes/class-m365-login-sync.php:1538
#: includes/class-m365-login-sync.php:958 includes/class-m365-login-sync.php:1654
msgid "no longer a member of the sync groups"
msgstr "kein Mitglied der Sync-Gruppen mehr"
#. translators: 1: e-mail address, 2: reason
#: includes/class-m365-login-sync.php:954
#: includes/class-m365-login-sync.php:978
msgid "%1$s: %2$s, but the account is protected (administrator or your own account) and was not changed."
msgstr "%1$s: %2$s, das Konto ist aber geschützt (Administrator oder dein eigenes Konto) und wurde nicht geändert."
#. translators: %s: e-mail address
#: includes/class-m365-login-sync.php:987
#: includes/class-m365-login-sync.php:1011
msgid "%s: no valid user to receive the content is selected, so the account is deactivated instead of deleted."
msgstr "%s: Es ist kein gültiger Benutzer für die Übernahme der Inhalte ausgewählt, deshalb wird das Konto deaktiviert statt gelöscht."
#. translators: 1: e-mail address, 2: reason
#: includes/class-m365-login-sync.php:996
#: includes/class-m365-login-sync.php:1020
msgid "%1$s: account deleted (%2$s)."
msgstr "%1$s: Konto gelöscht (%2$s)."
#. translators: 1: e-mail address, 2: reason
#: includes/class-m365-login-sync.php:1006
#: includes/class-m365-login-sync.php:1029
msgid "%1$s: account deactivated (%2$s)."
msgstr "%1$s: Konto deaktiviert (%2$s)."
#: includes/class-m365-login-sync.php:1085
#: includes/class-m365-login-sync.php:1108
msgid "Microsoft Graph refused the request. Grant the application permissions \"User.Read.All\" and \"GroupMember.Read.All\" with admin consent in Entra ID."
msgstr "Microsoft Graph hat die Anfrage abgelehnt. Erteile in Entra ID die Anwendungsberechtigungen „User.Read.All“ und „GroupMember.Read.All“ mit Administratorzustimmung."
#. translators: %s: error message
#: includes/class-m365-login-sync.php:1088
#: includes/class-m365-login-sync.php:1111
msgid "Microsoft Graph error: %s"
msgstr "Microsoft-Graph-Fehler: %s"
#: includes/class-m365-login-sync.php:1106
#: includes/class-m365-login-sync.php:1129
msgid "Log truncated."
msgstr "Protokoll gekürzt."
#. translators: 1: e-mail address, 2: error message
#: includes/class-m365-login-sync.php:1168
#: includes/class-m365-login-sync.php:1205
msgid "%1$s: profile photo could not be read: %2$s"
msgstr "%1$s: Profilbild konnte nicht gelesen werden: %2$s"
#. translators: %s: e-mail address
#: includes/class-m365-login-sync.php:1176
msgid "%s: profile photo removed."
msgstr "%s: Profilbild entfernt."
#: includes/class-m365-login-sync.php:1229 includes/class-m365-login-sync.php:1272
msgid "%s: profile photo updated."
msgstr "%s: Profilbild aktualisiert."
#. translators: %s: e-mail address
#: includes/class-m365-login-sync.php:1192
#: includes/class-m365-login-sync.php:1248
msgid "%s: profile photo could not be downloaded."
msgstr "%s: Profilbild konnte nicht heruntergeladen werden."
#. translators: %s: e-mail address
#: includes/class-m365-login-sync.php:1199
#: includes/class-m365-login-sync.php:1255
msgid "%s: profile photo is not a valid image or could not be saved."
msgstr "%s: Profilbild ist kein gültiges Bild oder konnte nicht gespeichert werden."
#. translators: %s: e-mail address
#: includes/class-m365-login-sync.php:1216
msgid "%s: profile photo updated."
msgstr "%s: Profilbild aktualisiert."
#. translators: %d: number of photos
#: includes/class-m365-login-sync.php:1278
msgid "%d changed profile photo will be downloaded in the next run (download limit per run reached)."
msgid_plural "%d changed profile photos will be downloaded in the next run (download limit per run reached)."
msgstr[0] "%d geändertes Profilbild wird im nächsten Lauf heruntergeladen (Download-Limit pro Lauf erreicht)."
msgstr[1] "%d geänderte Profilbilder werden im nächsten Lauf heruntergeladen (Download-Limit pro Lauf erreicht)."
#: includes/class-m365-login-sync.php:1433 includes/class-m365-login-sync.php:1566
#. translators: %s: e-mail address
#: includes/class-m365-login-sync.php:1293
msgid "%s: profile photo removed."
msgstr "%s: Profilbild entfernt."
#. translators: %d: number of photos
#: includes/class-m365-login-sync.php:1321
msgid "Profile photo sync is off: %d stored photo removed."
msgid_plural "Profile photo sync is off: %d stored photos removed."
msgstr[0] "Profilbild-Sync ist aus: %d gespeichertes Profilbild entfernt."
msgstr[1] "Profilbild-Sync ist aus: %d gespeicherte Profilbilder entfernt."
#: includes/class-m365-login-sync.php:1549 includes/class-m365-login-sync.php:1682
msgid "Microsoft 365"
msgstr "Microsoft 365"
#: includes/class-m365-login-sync.php:1451
#: includes/class-m365-login-sync.php:1567
msgid "Deactivated"
msgstr "Deaktiviert"
#: includes/class-m365-login-sync.php:1454
#: includes/class-m365-login-sync.php:1570
msgid "Imported"
msgstr "Importiert"
#: includes/class-m365-login-sync.php:1456
#: includes/class-m365-login-sync.php:1572
msgid "Linked"
msgstr "Verknüpft"
#: includes/class-m365-login-sync.php:1484
#: includes/class-m365-login-sync.php:1600
msgid "Reactivate"
msgstr "Reaktivieren"
#: includes/class-m365-login-sync.php:1484
#: includes/class-m365-login-sync.php:1600
msgid "Deactivate"
msgstr "Deaktivieren"
#: includes/class-m365-login-sync.php:1517
#: includes/class-m365-login-sync.php:1633
msgid "The account has been deactivated and signed out everywhere."
msgstr "Das Konto wurde deaktiviert und überall abgemeldet."
#: includes/class-m365-login-sync.php:1518
#: includes/class-m365-login-sync.php:1634
msgid "The account has been reactivated."
msgstr "Das Konto wurde reaktiviert."
#. translators: 1: date, 2: reason
#: includes/class-m365-login-sync.php:1542
#: includes/class-m365-login-sync.php:1658
msgid "Deactivated since %1$s (%2$s)"
msgstr "Deaktiviert seit %1$s (%2$s)"
#. translators: 1: date, 2: reason
#: includes/class-m365-login-sync.php:1544
#: includes/class-m365-login-sync.php:1660
msgid "manually"
msgstr "manuell"
#. translators: 1: date, 2: reason
#: includes/class-m365-login-sync.php:1546
#: includes/class-m365-login-sync.php:1662
msgid "Status"
msgstr "Status"
#: includes/class-m365-login-sync.php:1549
#: includes/class-m365-login-sync.php:1665
msgid "Object ID"
msgstr "Objekt-ID"
#: includes/class-m365-login-sync.php:1553
#: includes/class-m365-login-sync.php:1669
msgid "Last sync"
msgstr "Letzter Sync"
#: includes/class-m365-login-sync.php:1575
#: includes/class-m365-login-sync.php:1691
msgid "These values are managed by the Microsoft 365 user sync and overwritten on the next run."
msgstr "Diese Werte verwaltet der Microsoft-365-Benutzer-Sync; sie werden beim nächsten Lauf überschrieben."