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

@ -122,7 +122,7 @@ msgstr ""
msgid "Move up"
msgstr ""
#: 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 ""
@ -426,7 +426,7 @@ msgid "Selected Microsoft 365 attributes are copied into the WordPress profile o
msgstr ""
#: 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."
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 ""
#: includes/class-m365-login-admin.php:647
@ -1117,7 +1117,7 @@ msgstr ""
msgid "Too many sign-in attempts from your connection. Please wait a few minutes and try again."
msgstr ""
#: 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 ""
@ -1173,15 +1173,15 @@ msgstr ""
msgid "The certificate has already expired."
msgstr ""
#: includes/class-m365-login-graph.php:375
#: includes/class-m365-login-graph.php:434
msgid "Group"
msgstr ""
#: includes/class-m365-login-graph.php:377
#: includes/class-m365-login-graph.php:436
msgid "Security group"
msgstr ""
#: includes/class-m365-login-graph.php:379
#: includes/class-m365-login-graph.php:438
msgid "Microsoft 365 group"
msgstr ""
@ -1233,293 +1233,312 @@ msgstr ""
msgid "User sync: \"Delete\" needs a user who receives the posts of deleted accounts. Until one is selected, accounts are deactivated instead."
msgstr ""
#: includes/class-m365-login-sync.php:109
#: includes/class-m365-login-sync.php:110
msgid "Display name"
msgstr ""
#: includes/class-m365-login-sync.php:113
#: includes/class-m365-login-sync.php:114
msgid "First name"
msgstr ""
#: includes/class-m365-login-sync.php:117
#: includes/class-m365-login-sync.php:118
msgid "Last name"
msgstr ""
#: includes/class-m365-login-sync.php:121
#: includes/class-m365-login-sync.php:122
msgid "Profile photo (used as avatar)"
msgstr ""
#: includes/class-m365-login-sync.php:125
#: includes/class-m365-login-sync.php:126
msgid "Job title"
msgstr ""
#: includes/class-m365-login-sync.php:129
#: includes/class-m365-login-sync.php:130
msgid "Department"
msgstr ""
#: includes/class-m365-login-sync.php:133
#: includes/class-m365-login-sync.php:134
msgid "Company"
msgstr ""
#: includes/class-m365-login-sync.php:137
#: includes/class-m365-login-sync.php:138
msgid "Office"
msgstr ""
#: includes/class-m365-login-sync.php:141
#: includes/class-m365-login-sync.php:142
msgid "Employee ID"
msgstr ""
#: includes/class-m365-login-sync.php:145
#: includes/class-m365-login-sync.php:146
msgid "Business phone"
msgstr ""
#: includes/class-m365-login-sync.php:149
#: includes/class-m365-login-sync.php:150
msgid "Mobile phone"
msgstr ""
#: includes/class-m365-login-sync.php:153
#: includes/class-m365-login-sync.php:154
msgid "Street address"
msgstr ""
#: includes/class-m365-login-sync.php:157
#: includes/class-m365-login-sync.php:158
msgid "Postal code"
msgstr ""
#: includes/class-m365-login-sync.php:161
#: includes/class-m365-login-sync.php:162
msgid "City"
msgstr ""
#: includes/class-m365-login-sync.php:165
#: includes/class-m365-login-sync.php:166
msgid "State / province"
msgstr ""
#: includes/class-m365-login-sync.php:169
#: includes/class-m365-login-sync.php:170
msgid "Country"
msgstr ""
#: includes/class-m365-login-sync.php:173
#: includes/class-m365-login-sync.php:174
msgid "Language (sets the admin language if installed)"
msgstr ""
#: 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 ""
#: 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 ""
#: 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 ""
#: 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 ""
#. 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] ""
msgstr[1] ""
#. 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 ""
#. 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 ""
#. 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 ""
#. 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 ""
#. 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 ""
#: 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 ""
#. 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 ""
#. 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 ""
#. 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 ""
#. 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 ""
#. 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 ""
#. 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 ""
#. translators: %s: e-mail address
#: includes/class-m365-login-sync.php:741
#: includes/class-m365-login-sync.php:749
msgid "e-mail"
msgstr ""
#. translators: %s: profile field
#: includes/class-m365-login-sync.php:799
msgid "%s removed"
msgstr ""
#. 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 ""
#. translators: %s: role names
#: includes/class-m365-login-sync.php:891
#: includes/class-m365-login-sync.php:915
msgid "roles: %s"
msgstr ""
#: 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 ""
#: 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 ""
#. 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 ""
#. 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 ""
#. 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 ""
#. 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 ""
#: 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 ""
#. translators: %s: error message
#: includes/class-m365-login-sync.php:1088
#: includes/class-m365-login-sync.php:1111
msgid "Microsoft Graph error: %s"
msgstr ""
#: includes/class-m365-login-sync.php:1106
#: includes/class-m365-login-sync.php:1129
msgid "Log truncated."
msgstr ""
#. 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 ""
#. translators: %s: e-mail address
#: includes/class-m365-login-sync.php:1176
msgid "%s: profile photo removed."
#: includes/class-m365-login-sync.php:1229 includes/class-m365-login-sync.php:1272
msgid "%s: profile photo updated."
msgstr ""
#. 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 ""
#. 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 ""
#. 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] ""
msgstr[1] ""
#. translators: %s: e-mail address
#: includes/class-m365-login-sync.php:1216
msgid "%s: profile photo updated."
#: includes/class-m365-login-sync.php:1293
msgid "%s: profile photo removed."
msgstr ""
#: includes/class-m365-login-sync.php:1433 includes/class-m365-login-sync.php:1566
#. 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] ""
msgstr[1] ""
#: includes/class-m365-login-sync.php:1549 includes/class-m365-login-sync.php:1682
msgid "Microsoft 365"
msgstr ""
#: includes/class-m365-login-sync.php:1451
#: includes/class-m365-login-sync.php:1567
msgid "Deactivated"
msgstr ""
#: includes/class-m365-login-sync.php:1454
#: includes/class-m365-login-sync.php:1570
msgid "Imported"
msgstr ""
#: includes/class-m365-login-sync.php:1456
#: includes/class-m365-login-sync.php:1572
msgid "Linked"
msgstr ""
#: includes/class-m365-login-sync.php:1484
#: includes/class-m365-login-sync.php:1600
msgid "Reactivate"
msgstr ""
#: includes/class-m365-login-sync.php:1484
#: includes/class-m365-login-sync.php:1600
msgid "Deactivate"
msgstr ""
#: 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 ""
#: includes/class-m365-login-sync.php:1518
#: includes/class-m365-login-sync.php:1634
msgid "The account has been reactivated."
msgstr ""
#. 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 ""
#. translators: 1: date, 2: reason
#: includes/class-m365-login-sync.php:1544
#: includes/class-m365-login-sync.php:1660
msgid "manually"
msgstr ""
#. translators: 1: date, 2: reason
#: includes/class-m365-login-sync.php:1546
#: includes/class-m365-login-sync.php:1662
msgid "Status"
msgstr ""
#: includes/class-m365-login-sync.php:1549
#: includes/class-m365-login-sync.php:1665
msgid "Object ID"
msgstr ""
#: includes/class-m365-login-sync.php:1553
#: includes/class-m365-login-sync.php:1669
msgid "Last sync"
msgstr ""
#: 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 ""