Simple Local Avatars - Version 2.3.0

Version Description

  • Added: Crop screen (props @jeffpaul, @helen, @ajmaurya99, @Antonio-Lagun, @faisal-alvi).
  • Added: Avatar preview for Subscribers (props @ankitguptaindia, @dinhtungdu, @dkotter).
  • Added: More robust multisite support and shared avatar setting (props @adamsilverstein, @helen, @jeffpaul, @dkotter, @faisal-alvi, @holle75).
  • Added: Settings link to plugin action links (props @rahulsprajapati, @jeffpaul, @iamdharmesh).
  • Added: Dashboard setting and WP-CLI command to migrate avatars from WP User Avatars (props @jeffpaul, @claytoncollie, @helen, @faisal-alvi).
  • Added: Option to clear cache of user meta to remove image sizes that do not exist (props @jeffpaul, @ituk, @dinhtungdu, @sparkbold, @thrijith).
  • Added: Package file (props @faisal-alvi, @jeffpaul, @claytoncollie, @cadic).
  • Added: PHP Unit Tests (props @faisal-alvi, @iamdharmesh).
  • Added: "No Response" GitHub Action (props @jeffpaul).
  • Changed: Bump WordPress "tested up to" version to 5.9 (props @jeffpaul, @ankitguptaindia, @dinhtungdu, @phpbits).
  • Changed: - Bump WordPress "tested up to" version to 6.0 (props @ajmaurya99 via #110).
  • Changed: Format admin script (props @thrijith, @dinhtungdu).
  • Fixed: Media ID as string in REST API (props @diodoe, @dinhtungdu, @dkotter).
  • Fixed: Avatar rating text is not translated properly if a user has a custom language Set (props @ActuallyConnor, @faisal-alvi).
  • Security: PHP 8 compatibility (props @faisal-alvi, @dkotter, @Sidsector9).
  • Security: Bump rmccue/requests from 1.7.0 to 1.8.0 (props dependabot@).
  • Security: Bump nanoid from 3.1.28 to 3.2.0 (props dependabot@).
  • Security: Bump minimist from 1.2.5 to 1.2.6 (props dependabot@).
Download this release

Release Info

Developer 10up
Plugin Icon 128x128 Simple Local Avatars
Version 2.3.0
Comparing to
See all releases

Code changes from version 2.2.0 to 2.3.0

dist/simple-local-avatars.asset.php ADDED
@@ -0,0 +1 @@
 
1
+ <?php return array('dependencies' => array('wp-polyfill'), 'version' => 'b38d7e6f94a7710dfed66c3983d38d30');
dist/simple-local-avatars.js ADDED
@@ -0,0 +1 @@
 
1
+ !function(){let e,a,t,r,i,o,s,l,n,c=!1;function m(e){void 0===a&&(t=document.getElementById("simple-local-avatar-ratings"),a=jQuery(document.getElementById("simple-local-avatar-spinner")),r=document.getElementById("simple-local-avatar-photo"),i=jQuery(t).closest("form").find("input[type=submit]")),"unlock"===e?(c=!1,i.removeAttr("disabled"),a.hide()):(c=!0,i.attr("disabled","disabled"),a.show())}function p(e,a){const t=a.get("control"),r=e.get("width"),i=e.get("height");let o=parseInt(t.params.width,10),s=parseInt(t.params.height,10);const l=o/s;a.set("canSkipCrop",!t.mustBeCropped(!1,!1,o,s,r,i));const n=o,c=s;r/i>l?(s=i,o=s*l):(o=r,s=o/l);const m=(r-o)/2,p=(i-s)/2;return{handles:!0,keys:!0,instance:!0,persistent:!0,imageWidth:r,imageHeight:i,minWidth:n>o?o:n,minHeight:c>s?s:c,x1:m,y1:p,x2:o+m,y2:s+p,aspectRatio:`${o}:${s}`}}function u(e,a,i,o){const s={};s.url=e,s.thumbnail_url=e,s.timestamp=_.now(),a&&(s.attachment_id=a),i&&(s.width=i),o&&(s.height=o),m("lock"),jQuery.post(ajaxurl,{action:"assign_simple_local_avatar_media",media_id:a,user_id:i10n_SimpleLocalAvatars.user_id,_wpnonce:i10n_SimpleLocalAvatars.mediaNonce}).done((function(e){""!==e&&(r.innerHTML=e,jQuery("#simple-local-avatar-remove").show(),t.disabled=!1)})).always((function(){m("unlock")}))}jQuery(document).ready((function(a){s=a("#simple-local-avatar"),o=a("#simple-local-avatar-photo img"),n=o.attr("src"),t=a("#simple-local-avatar-ratings"),r=a("#simple-local-avatar-photo"),a("#simple-local-avatar-media").on("click",(function(a){if(a.preventDefault(),c)return;const i={id:"control-id",params:{flex_width:!1,flex_height:!1,width:200,height:200},mustBeCropped:function(e,a,t,r,i,o){return i!==t||o!==r}};e=wp.media({button:{text:i10n_SimpleLocalAvatars.selectCrop,close:!1},states:[new wp.media.controller.Library({title:i10n_SimpleLocalAvatars.selectCrop,library:wp.media.query({type:"image"}),multiple:!1,date:!1,priority:20,suggestedWidth:200,suggestedHeight:200}),new wp.media.controller.CustomizeImageCropper({imgSelectOptions:p,control:i})]}),e.on("cropped",(function(e){const{url:a}=e;u(a,e.id,e.width,e.height)})),e.on("skippedcrop",(function(e){const a=e.get("url"),t=e.get("width"),r=e.get("height");u(a,e.id,t,r)})),e.on("select",(function(){const a=e.state().get("selection").first().toJSON();var o;i.params.width!==a.width||i.params.height!==a.height||i.params.flex_width||i.params.flex_height?e.setState("cropper"):(a.dst_width=a.width,a.dst_height=a.height,o=a,m("lock"),jQuery.post(ajaxurl,{action:"assign_simple_local_avatar_media",media_id:o.id,user_id:i10n_SimpleLocalAvatars.user_id,_wpnonce:i10n_SimpleLocalAvatars.mediaNonce}).done((function(e){""!==e&&(r.innerHTML=e,jQuery("#simple-local-avatar-remove").show(),t.disabled=!1,m("unlock"))})).always((function(){m("unlock")})),e.close())})),e.open()})),a("#simple-local-avatar-remove").on("click",(function(e){e.preventDefault(),c||(m("lock"),a.get(ajaxurl,{action:"remove_simple_local_avatar",user_id:i10n_SimpleLocalAvatars.user_id,_wpnonce:i10n_SimpleLocalAvatars.deleteNonce}).done((function(e){""!==e&&(r.innerHTML=e,a("#simple-local-avatar-remove").hide(),t.disabled=!0)})).always((function(){m("unlock")})))})),s.on("change",(function(e){o.attr("srcset",""),o.attr("height","auto"),URL.revokeObjectURL(l),e.target.files.length>0?(l=URL.createObjectURL(e.target.files[0]),o.attr("src",l)):o.attr("src",n)})),a(document.getElementById("simple-local-avatars-migrate-from-wp-user-avatar")).on("click",(function(e){e.preventDefault(),jQuery.post(ajaxurl,{action:"migrate_from_wp_user_avatar",migrateFromWpUserAvatarNonce:i10n_SimpleLocalAvatars.migrateFromWpUserAvatarNonce}).always((function(){a(".simple-local-avatars-migrate-from-wp-user-avatar-progress").empty(),a(".simple-local-avatars-migrate-from-wp-user-avatar-progress").text(i10n_SimpleLocalAvatars.migrateFromWpUserAvatarProgress)})).done((function(e){a(".simple-local-avatars-migrate-from-wp-user-avatar-progress").empty();const t=a.parseJSON(e).count;0===t&&a(".simple-local-avatars-migrate-from-wp-user-avatar-progress").text(i10n_SimpleLocalAvatars.migrateFromWpUserAvatarFailure),t>0&&a(".simple-local-avatars-migrate-from-wp-user-avatar-progress").text(i10n_SimpleLocalAvatars.migrateFromWpUserAvatarSuccess+": "+t),setTimeout((function(){a(".simple-local-avatars-migrate-from-wp-user-avatar-progress").empty()}),5e3)}))}))}))}();
includes/class-simple-local-avatars.php CHANGED
@@ -1,17 +1,73 @@
1
  <?php
2
  /**
3
- * Class: Simple_Local_Avatars
4
  * Adds an avatar upload field to user profiles.
 
 
 
 
 
 
5
  */
6
  class Simple_Local_Avatars {
7
- private $user_id_being_edited, $avatar_upload_error, $remove_nonce, $avatar_ratings;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8
  public $options;
9
 
10
  /**
11
  * Set up the hooks and default values
12
  */
13
  public function __construct() {
 
 
14
  $this->options = (array) get_option( 'simple_local_avatars' );
 
 
15
  $this->avatar_ratings = array(
16
  'G' => __( 'G &#8212; Suitable for all audiences', 'simple-local-avatars' ),
17
  'PG' => __( 'PG &#8212; Possibly offensive, usually for audiences 13 and above', 'simple-local-avatars' ),
@@ -19,14 +75,35 @@ class Simple_Local_Avatars {
19
  'X' => __( 'X &#8212; Even more mature than above', 'simple-local-avatars' ),
20
  );
21
 
22
- $this->add_hooks();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
  }
24
 
25
  /**
26
  * Register actions and filters.
27
  */
28
  public function add_hooks() {
 
 
 
29
  add_filter( 'pre_get_avatar_data', array( $this, 'get_avatar_data' ), 10, 2 );
 
30
 
31
  add_action( 'admin_init', array( $this, 'admin_init' ) );
32
 
@@ -42,6 +119,104 @@ class Simple_Local_Avatars {
42
  add_action( 'user_edit_form_tag', array( $this, 'user_edit_form_tag' ) );
43
 
44
  add_action( 'rest_api_init', array( $this, 'register_rest_fields' ) );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
45
  }
46
 
47
  /**
@@ -104,12 +279,13 @@ class Simple_Local_Avatars {
104
  public function get_simple_local_avatar_url( $id_or_email, $size ) {
105
  if ( is_numeric( $id_or_email ) ) {
106
  $user_id = (int) $id_or_email;
107
- } elseif ( is_string( $id_or_email ) && ( $user = get_user_by( 'email', $id_or_email ) ) ) {
108
- $user_id = $user->ID;
109
  } elseif ( is_object( $id_or_email ) && ! empty( $id_or_email->user_id ) ) {
110
  $user_id = (int) $id_or_email->user_id;
111
  } elseif ( $id_or_email instanceof WP_Post && ! empty( $id_or_email->post_author ) ) {
112
  $user_id = (int) $id_or_email->post_author;
 
 
 
113
  }
114
 
115
  if ( empty( $user_id ) ) {
@@ -117,17 +293,18 @@ class Simple_Local_Avatars {
117
  }
118
 
119
  // Fetch local avatar from meta and make sure it's properly set.
120
- $local_avatars = get_user_meta( $user_id, 'simple_local_avatar', true );
121
  if ( empty( $local_avatars['full'] ) ) {
122
  return '';
123
  }
124
 
125
  // check rating
126
- $avatar_rating = get_user_meta( $user_id, 'simple_local_avatar_rating', true );
127
- if ( ! empty( $avatar_rating ) && 'G' !== $avatar_rating && ( $site_rating = get_option( 'avatar_rating' ) ) ) {
 
128
  $ratings = array_keys( $this->avatar_ratings );
129
- $site_rating_weight = array_search( $site_rating, $ratings );
130
- $avatar_rating_weight = array_search( $avatar_rating, $ratings );
131
  if ( false !== $avatar_rating_weight && $avatar_rating_weight > $site_rating_weight ) {
132
  return '';
133
  }
@@ -135,8 +312,20 @@ class Simple_Local_Avatars {
135
 
136
  // handle "real" media
137
  if ( ! empty( $local_avatars['media_id'] ) ) {
 
 
 
 
 
 
 
 
 
 
 
 
138
  // has the media been deleted?
139
- if ( ! $avatar_full_path = get_attached_file( $local_avatars['media_id'] ) ) {
140
  return '';
141
  }
142
  }
@@ -171,7 +360,7 @@ class Simple_Local_Avatars {
171
  }
172
 
173
  // save updated avatar sizes
174
- update_user_meta( $user_id, 'simple_local_avatar', $local_avatars );
175
 
176
  endif;
177
  }
@@ -220,7 +409,8 @@ class Simple_Local_Avatars {
220
  */
221
  public function admin_init() {
222
  // upgrade pre 2.0 option
223
- if ( $old_ops = get_option( 'simple_local_avatars_caps' ) ) {
 
224
  if ( ! empty( $old_ops['simple_local_avatars_caps'] ) ) {
225
  update_option( 'simple_local_avatars', array( 'caps' => 1 ) );
226
  }
@@ -236,8 +426,9 @@ class Simple_Local_Avatars {
236
  'discussion',
237
  'avatars',
238
  array(
239
- 'key' => 'only',
240
- 'desc' => __( 'Only allow local avatars (still uses Gravatar for default avatars)', 'simple-local-avatars' ),
 
241
  )
242
  );
243
  add_settings_field(
@@ -247,19 +438,191 @@ class Simple_Local_Avatars {
247
  'discussion',
248
  'avatars',
249
  array(
250
- 'key' => 'caps',
251
- 'desc' => __( 'Only allow users with file upload capabilities to upload local avatars (Authors and above)', 'simple-local-avatars' ),
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
252
  )
253
  );
254
  }
255
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
256
  /**
257
  * Add scripts to the profile editing page
258
  *
259
  * @param string $hook_suffix Page hook
260
  */
261
  public function admin_enqueue_scripts( $hook_suffix ) {
262
- if ( 'profile.php' !== $hook_suffix && 'user-edit.php' !== $hook_suffix ) {
 
 
 
 
 
 
 
 
 
 
263
  return;
264
  }
265
 
@@ -267,21 +630,26 @@ class Simple_Local_Avatars {
267
  wp_enqueue_media();
268
  }
269
 
270
- $user_id = ( 'profile.php' === $hook_suffix ) ? get_current_user_id() : (int) $_GET['user_id'];
 
271
 
272
  $this->remove_nonce = wp_create_nonce( 'remove_simple_local_avatar_nonce' );
273
 
274
- $script_name_append = ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) ? '.dev' : '';
275
- wp_enqueue_script( 'simple-local-avatars', plugins_url( '', dirname( __FILE__ ) ) . '/simple-local-avatars' . $script_name_append . '.js', array( 'jquery' ), false, true );
276
  wp_localize_script(
277
  'simple-local-avatars',
278
  'i10n_SimpleLocalAvatars',
279
  array(
280
- 'user_id' => $user_id,
281
- 'insertMediaTitle' => __( 'Choose an Avatar', 'simple-local-avatars' ),
282
- 'insertIntoPost' => __( 'Set as avatar', 'simple-local-avatars' ),
283
- 'deleteNonce' => $this->remove_nonce,
284
- 'mediaNonce' => wp_create_nonce( 'assign_simple_local_avatar_nonce' ),
 
 
 
 
 
285
  )
286
  );
287
  }
@@ -295,6 +663,11 @@ class Simple_Local_Avatars {
295
  public function sanitize_options( $input ) {
296
  $new_input['caps'] = empty( $input['caps'] ) ? 0 : 1;
297
  $new_input['only'] = empty( $input['only'] ) ? 0 : 1;
 
 
 
 
 
298
  return $new_input;
299
  }
300
 
@@ -307,21 +680,51 @@ class Simple_Local_Avatars {
307
  $args = wp_parse_args(
308
  $args,
309
  array(
310
- 'key' => '',
311
- 'desc' => '',
 
312
  )
313
  );
314
 
315
- if ( empty( $this->options[ $args['key'] ] ) ) {
316
- $this->options[ $args['key'] ] = 0;
317
  }
318
 
319
- echo '
 
320
  <label for="simple-local-avatars-' . esc_attr( $args['key'] ) . '">
321
  <input type="checkbox" name="simple_local_avatars[' . esc_attr( $args['key'] ) . ']" id="simple-local-avatars-' . esc_attr( $args['key'] ) . '" value="1" ' . checked( $this->options[ $args['key'] ], 1, false ) . ' />
322
  ' . esc_html( $args['desc'] ) . '
323
  </label>
324
  ';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
325
  }
326
 
327
  /**
@@ -330,92 +733,91 @@ class Simple_Local_Avatars {
330
  * @param object $profileuser User object
331
  */
332
  public function edit_user_profile( $profileuser ) {
333
- ?>
334
- <div id="simple-local-avatar-section">
335
- <h3><?php esc_html_e( 'Avatar', 'simple-local-avatars' ); ?></h3>
336
-
337
- <table class="form-table">
338
- <tr class="upload-avatar-row">
339
- <th scope="row"><label for="simple-local-avatar"><?php esc_html_e( 'Upload Avatar', 'simple-local-avatars' ); ?></label></th>
340
- <td style="width: 50px;" id="simple-local-avatar-photo">
341
- <?php
342
- add_filter( 'pre_option_avatar_rating', '__return_null' ); // ignore ratings here
343
- echo get_simple_local_avatar( $profileuser->ID );
344
- remove_filter( 'pre_option_avatar_rating', '__return_null' );
345
- ?>
346
- </td>
347
- <td>
348
- <?php
349
- if ( ! $upload_rights = current_user_can( 'upload_files' ) ) {
350
- $upload_rights = empty( $this->options['caps'] );
351
- }
352
-
353
- if ( $upload_rights ) {
354
- do_action( 'simple_local_avatar_notices' );
355
- wp_nonce_field( 'simple_local_avatar_nonce', '_simple_local_avatar_nonce', false );
356
- $remove_url = add_query_arg(
357
- array(
358
- 'action' => 'remove-simple-local-avatar',
359
- 'user_id' => $profileuser->ID,
360
- '_wpnonce' => $this->remove_nonce,
361
- )
362
- );
363
- ?>
364
- <?php
365
- // if user is author and above hide the choose file option
366
- // force them to use the WP Media Selector
367
- if ( ! current_user_can( 'upload_files' ) ) {
368
- ?>
369
- <p style="display: inline-block; width: 26em;">
370
- <span class="description"><?php esc_html_e( 'Choose an image from your computer:' ); ?></span><br />
371
- <input type="file" name="simple-local-avatar" id="simple-local-avatar" class="standard-text" />
372
- <span class="spinner" id="simple-local-avatar-spinner"></span>
373
- </p>
374
- <?php } ?>
375
- <p>
376
- <?php if ( current_user_can( 'upload_files' ) && did_action( 'wp_enqueue_media' ) ) : ?>
377
- <a href="#" class="button hide-if-no-js" id="simple-local-avatar-media"><?php esc_html_e( 'Choose from Media Library', 'simple-local-avatars' ); ?></a> &nbsp;
378
- <?php endif; ?>
379
- <a
380
- href="<?php echo esc_url( $remove_url ); ?>"
381
- class="button item-delete submitdelete deletion"
382
- id="simple-local-avatar-remove"
383
- <?php echo empty( $profileuser->simple_local_avatar ) ? ' style="display:none;"' : ''; ?>
384
- >
385
- <?php esc_html_e( 'Delete local avatar', 'simple-local-avatars' ); ?>
386
- </a>
387
- </p>
388
- <?php
389
- } else {
390
- if ( empty( $profileuser->simple_local_avatar ) ) {
391
- echo '<span class="description">' . esc_html__( 'No local avatar is set. Set up your avatar at Gravatar.com.', 'simple-local-avatars' ) . '</span>';
392
- } else {
393
- echo '<span class="description">' . esc_html__( 'You do not have media management permissions. To change your local avatar, contact the blog administrator.', 'simple-local-avatars' ) . '</span>';
394
- }
395
- }
396
- ?>
397
- </td>
398
- </tr>
399
- <tr class="ratings-row">
400
- <th scope="row"><?php esc_html_e( 'Rating' ); ?></th>
401
- <td colspan="2">
402
- <fieldset id="simple-local-avatar-ratings" <?php disabled( empty( $profileuser->simple_local_avatar ) ); ?>>
403
- <legend class="screen-reader-text"><span><?php esc_html_e( 'Rating' ); ?></span></legend>
404
- <?php
405
- if ( empty( $profileuser->simple_local_avatar_rating ) || ! array_key_exists( $profileuser->simple_local_avatar_rating, $this->avatar_ratings ) ) {
406
- $profileuser->simple_local_avatar_rating = 'G';
407
- }
408
 
409
- foreach ( $this->avatar_ratings as $key => $rating ) :
410
- echo "\n\t<label><input type='radio' name='simple_local_avatar_rating' value='" . esc_attr( $key ) . "' " . checked( $profileuser->simple_local_avatar_rating, $key, false ) . "/> $rating</label><br />";
411
- endforeach;
412
- ?>
413
- <p class="description"><?php esc_html_e( 'If the local avatar is inappropriate for this site, Gravatar will be attempted.', 'simple-local-avatars' ); ?></p>
414
- </fieldset></td>
415
- </tr>
416
- </table>
417
- </div>
418
- <?php
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
419
  }
420
 
421
  /**
@@ -433,19 +835,20 @@ class Simple_Local_Avatars {
433
  */
434
  public function assign_new_user_avatar( $url_or_media_id, $user_id ) {
435
  // delete the old avatar
436
- $this->avatar_delete( $user_id ); // delete old images if successful
437
 
438
  $meta_value = array();
439
 
440
  // set the new avatar
441
- if ( is_int( $url_or_media_id ) ) {
442
  $meta_value['media_id'] = $url_or_media_id;
443
  $url_or_media_id = wp_get_attachment_url( $url_or_media_id );
444
  }
445
 
446
- $meta_value['full'] = $url_or_media_id;
 
447
 
448
- update_user_meta( $user_id, 'simple_local_avatar', $meta_value ); // save user information (overwriting old)
449
  }
450
 
451
  /**
@@ -466,6 +869,7 @@ class Simple_Local_Avatars {
466
  if ( false !== strpos( $_FILES['simple-local-avatar']['name'], '.php' ) ) {
467
  $this->avatar_upload_error = __( 'For security reasons, the extension ".php" cannot be in your file name.', 'simple-local-avatars' );
468
  add_action( 'user_profile_update_errors', array( $this, 'user_profile_update_errors' ) );
 
469
  return;
470
  }
471
 
@@ -498,6 +902,7 @@ class Simple_Local_Avatars {
498
  if ( is_wp_error( $avatar_id ) ) { // handle failures.
499
  $this->avatar_upload_error = '<strong>' . __( 'There was an error uploading the avatar:', 'simple-local-avatars' ) . '</strong> ' . esc_html( $avatar_id->get_error_message() );
500
  add_action( 'user_profile_update_errors', array( $this, 'user_profile_update_errors' ) );
 
501
  return;
502
  }
503
 
@@ -506,12 +911,12 @@ class Simple_Local_Avatars {
506
  endif;
507
 
508
  // Handle ratings
509
- if ( isset( $avatar_id ) || $avatar = get_user_meta( $user_id, 'simple_local_avatar', true ) ) {
510
  if ( empty( $_POST['simple_local_avatar_rating'] ) || ! array_key_exists( $_POST['simple_local_avatar_rating'], $this->avatar_ratings ) ) {
511
  $_POST['simple_local_avatar_rating'] = key( $this->avatar_ratings );
512
  }
513
 
514
- update_user_meta( $user_id, 'simple_local_avatar_rating', $_POST['simple_local_avatar_rating'] );
515
  }
516
  }
517
 
@@ -539,7 +944,7 @@ class Simple_Local_Avatars {
539
  $this->avatar_delete( $user_id ); // delete old images if successful
540
 
541
  if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
542
- echo get_simple_local_avatar( $user_id );
543
  }
544
  }
545
 
@@ -565,7 +970,7 @@ class Simple_Local_Avatars {
565
  $this->assign_new_user_avatar( $media_id, $user_id );
566
  }
567
 
568
- echo get_simple_local_avatar( $user_id );
569
 
570
  die;
571
  }
@@ -576,7 +981,7 @@ class Simple_Local_Avatars {
576
  * @param int $user_id User ID.
577
  */
578
  public function avatar_delete( $user_id ) {
579
- $old_avatars = (array) get_user_meta( $user_id, 'simple_local_avatar', true );
580
 
581
  if ( empty( $old_avatars ) ) {
582
  return;
@@ -599,8 +1004,8 @@ class Simple_Local_Avatars {
599
  }
600
  }
601
 
602
- delete_user_meta( $user_id, 'simple_local_avatar' );
603
- delete_user_meta( $user_id, 'simple_local_avatar_rating' );
604
  }
605
 
606
  /**
@@ -613,13 +1018,13 @@ class Simple_Local_Avatars {
613
  */
614
  public function unique_filename_callback( $dir, $name, $ext ) {
615
  $user = get_user_by( 'id', (int) $this->user_id_being_edited );
616
- $name = $base_name = sanitize_file_name( $user->display_name . '_avatar_' . time() );
617
 
618
  // ensure no conflicts with existing file names
619
  $number = 1;
620
  while ( file_exists( $dir . "/$name$ext" ) ) {
621
  $name = $base_name . '_' . $number;
622
- $number++;
623
  }
624
 
625
  return $name . $ext;
@@ -658,10 +1063,11 @@ class Simple_Local_Avatars {
658
  * @param object $user User object
659
  */
660
  public function get_avatar_rest( $user ) {
661
- $local_avatar = get_user_meta( $user['id'], 'simple_local_avatar', true );
662
  if ( empty( $local_avatar ) ) {
663
  return;
664
  }
 
665
  return $local_avatar;
666
  }
667
 
@@ -678,4 +1084,360 @@ class Simple_Local_Avatars {
678
  public function set_avatar_rest( $input, $user ) {
679
  $this->assign_new_user_avatar( $input['media_id'], $user->ID );
680
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
681
  }
1
  <?php
2
  /**
3
+ * Main Class file: Simple_Local_Avatars
4
  * Adds an avatar upload field to user profiles.
5
+ *
6
+ * @package SimpleLocalAvatars
7
+ */
8
+
9
+ /**
10
+ * Main SLA Class.
11
  */
12
  class Simple_Local_Avatars {
13
+ /**
14
+ * The user ID.
15
+ *
16
+ * @var int.
17
+ */
18
+ private $user_id_being_edited;
19
+
20
+ /**
21
+ * The upload error comment.
22
+ *
23
+ * @var string.
24
+ */
25
+ private $avatar_upload_error;
26
+
27
+ /**
28
+ * The nonce token.
29
+ *
30
+ * @var string
31
+ */
32
+ private $remove_nonce;
33
+
34
+ /**
35
+ * The ratings.
36
+ *
37
+ * @var array
38
+ */
39
+ private $avatar_ratings;
40
+
41
+ /**
42
+ * The meta key a user.
43
+ *
44
+ * @var string
45
+ */
46
+ private $user_key;
47
+
48
+ /**
49
+ * The meta key a user.
50
+ *
51
+ * @var string he meta key for ratings.
52
+ */
53
+ private $rating_key;
54
+
55
+ /**
56
+ * Configured setting values.
57
+ *
58
+ * @var array
59
+ */
60
  public $options;
61
 
62
  /**
63
  * Set up the hooks and default values
64
  */
65
  public function __construct() {
66
+ $this->add_hooks();
67
+
68
  $this->options = (array) get_option( 'simple_local_avatars' );
69
+ $this->user_key = 'simple_local_avatar';
70
+ $this->rating_key = 'simple_local_avatar_rating';
71
  $this->avatar_ratings = array(
72
  'G' => __( 'G &#8212; Suitable for all audiences', 'simple-local-avatars' ),
73
  'PG' => __( 'PG &#8212; Possibly offensive, usually for audiences 13 and above', 'simple-local-avatars' ),
75
  'X' => __( 'X &#8212; Even more mature than above', 'simple-local-avatars' ),
76
  );
77
 
78
+ if (
79
+ ! $this->is_avatar_shared() // Are we sharing avatars?
80
+ && (
81
+ ( // And either an ajax request not in the network admin.
82
+ defined( 'DOING_AJAX' ) && DOING_AJAX
83
+ && ! preg_match( '#^' . network_admin_url() . '#i', $_SERVER['HTTP_REFERER'] )
84
+ )
85
+ ||
86
+ ( // Or normal request not in the network admin.
87
+ ( ! defined( 'DOING_AJAX' ) || ! DOING_AJAX )
88
+ && ! is_network_admin()
89
+ )
90
+ )
91
+ && is_multisite()
92
+ ) {
93
+ $this->user_key = sprintf( $this->user_key . '_%d', get_current_blog_id() );
94
+ $this->rating_key = sprintf( $this->rating_key . '_%d', get_current_blog_id() );
95
+ }
96
  }
97
 
98
  /**
99
  * Register actions and filters.
100
  */
101
  public function add_hooks() {
102
+
103
+ add_filter( 'plugin_action_links_' . SLA_PLUGIN_BASENAME, array( $this, 'plugin_filter_action_links' ) );
104
+
105
  add_filter( 'pre_get_avatar_data', array( $this, 'get_avatar_data' ), 10, 2 );
106
+ add_filter( 'pre_option_simple_local_avatars', array( $this, 'pre_option_simple_local_avatars' ), 10, 1 );
107
 
108
  add_action( 'admin_init', array( $this, 'admin_init' ) );
109
 
119
  add_action( 'user_edit_form_tag', array( $this, 'user_edit_form_tag' ) );
120
 
121
  add_action( 'rest_api_init', array( $this, 'register_rest_fields' ) );
122
+
123
+ add_action( 'wp_ajax_migrate_from_wp_user_avatar', array( $this, 'ajax_migrate_from_wp_user_avatar' ) );
124
+
125
+ if ( defined( 'WP_CLI' ) && WP_CLI ) {
126
+ WP_CLI::add_command( 'simple-local-avatars migrate wp-user-avatar', array( $this, 'wp_cli_migrate_from_wp_user_avatar' ) );
127
+ }
128
+
129
+ add_action( 'admin_enqueue_scripts', array( $this, 'admin_scripts' ) );
130
+ add_action( 'wp_ajax_sla_clear_user_cache', array( $this, 'sla_clear_user_cache' ) );
131
+
132
+ add_action( 'wpmu_new_blog', array( $this, 'set_defaults' ) );
133
+ }
134
+
135
+ /**
136
+ * Determine if plugin is network activated.
137
+ *
138
+ * @param string $plugin The plugin slug to check.
139
+ *
140
+ * @return boolean
141
+ */
142
+ public static function is_network( $plugin ) {
143
+ $plugins = get_site_option( 'active_sitewide_plugins', array() );
144
+
145
+ if ( is_multisite() && isset( $plugins[ $plugin ] ) ) {
146
+ return true;
147
+ }
148
+
149
+ return false;
150
+ }
151
+
152
+ /**
153
+ * Get current plugin network mode
154
+ */
155
+ public function get_network_mode() {
156
+ if ( SLA_IS_NETWORK ) {
157
+ return get_site_option( 'simple_local_avatars_mode', 'default' );
158
+ }
159
+
160
+ return 'default';
161
+ }
162
+
163
+ /**
164
+ * Determines if settings handling is enforced on a network level
165
+ *
166
+ * Important: this is only meant for admin UI purposes.
167
+ *
168
+ * @return boolean
169
+ */
170
+ public function is_enforced() {
171
+ if (
172
+ ( ! is_network_admin() && ( SLA_IS_NETWORK && 'enforce' === $this->get_network_mode() ) )
173
+ ) {
174
+ return true;
175
+ }
176
+
177
+ return false;
178
+ }
179
+
180
+ /**
181
+ * Determine if avatars should be shared
182
+ *
183
+ * @return boolean
184
+ */
185
+ public function is_avatar_shared() {
186
+ if (
187
+ is_multisite() // Are we on multisite.
188
+ && ! isset( $this->options['shared'] ) // And our shared option doesn't exist.
189
+ || (
190
+ isset( $this->options['shared'] ) // Or our shared option is set.
191
+ && 1 === $this->options['shared']
192
+ )
193
+ ) {
194
+ return true;
195
+ }
196
+
197
+ return false;
198
+ }
199
+
200
+ /**
201
+ * Add the settings action link to the plugin page.
202
+ *
203
+ * @param array $links The Action links for the plugin.
204
+ *
205
+ * @return array
206
+ */
207
+ public function plugin_filter_action_links( $links ) {
208
+
209
+ if ( ! is_array( $links ) ) {
210
+ return $links;
211
+ }
212
+
213
+ $links['settings'] = sprintf(
214
+ '<a href="%s"> %s </a>',
215
+ esc_url( admin_url( 'options-discussion.php' ) ),
216
+ __( 'Settings', 'simple-local-avatars' )
217
+ );
218
+
219
+ return $links;
220
  }
221
 
222
  /**
279
  public function get_simple_local_avatar_url( $id_or_email, $size ) {
280
  if ( is_numeric( $id_or_email ) ) {
281
  $user_id = (int) $id_or_email;
 
 
282
  } elseif ( is_object( $id_or_email ) && ! empty( $id_or_email->user_id ) ) {
283
  $user_id = (int) $id_or_email->user_id;
284
  } elseif ( $id_or_email instanceof WP_Post && ! empty( $id_or_email->post_author ) ) {
285
  $user_id = (int) $id_or_email->post_author;
286
+ } elseif ( is_string( $id_or_email ) ) {
287
+ $user = get_user_by( 'email', $id_or_email );
288
+ $user_id = $user ? $user->ID : '';
289
  }
290
 
291
  if ( empty( $user_id ) ) {
293
  }
294
 
295
  // Fetch local avatar from meta and make sure it's properly set.
296
+ $local_avatars = get_user_meta( $user_id, $this->user_key, true );
297
  if ( empty( $local_avatars['full'] ) ) {
298
  return '';
299
  }
300
 
301
  // check rating
302
+ $avatar_rating = get_user_meta( $user_id, $this->rating_key, true );
303
+ $site_rating = get_option( 'avatar_rating' );
304
+ if ( ! empty( $avatar_rating ) && 'G' !== $avatar_rating && $site_rating ) {
305
  $ratings = array_keys( $this->avatar_ratings );
306
+ $site_rating_weight = array_search( $site_rating, $ratings, true );
307
+ $avatar_rating_weight = array_search( $avatar_rating, $ratings, true );
308
  if ( false !== $avatar_rating_weight && $avatar_rating_weight > $site_rating_weight ) {
309
  return '';
310
  }
312
 
313
  // handle "real" media
314
  if ( ! empty( $local_avatars['media_id'] ) ) {
315
+ // If using shared avatars, make sure we validate the URL on the main site.
316
+ if ( $this->is_avatar_shared() ) {
317
+ $origin_blog_id = isset( $local_avatars['blog_id'] ) && ! empty( $local_avatars['blog_id'] ) ? $local_avatars['blog_id'] : get_main_site_id();
318
+ switch_to_blog( $origin_blog_id );
319
+ }
320
+
321
+ $avatar_full_path = get_attached_file( $local_avatars['media_id'] );
322
+
323
+ if ( $this->is_avatar_shared() ) {
324
+ restore_current_blog();
325
+ }
326
+
327
  // has the media been deleted?
328
+ if ( ! $avatar_full_path ) {
329
  return '';
330
  }
331
  }
360
  }
361
 
362
  // save updated avatar sizes
363
+ update_user_meta( $user_id, $this->user_key, $local_avatars );
364
 
365
  endif;
366
  }
409
  */
410
  public function admin_init() {
411
  // upgrade pre 2.0 option
412
+ $old_ops = get_option( 'simple_local_avatars_caps' );
413
+ if ( $old_ops ) {
414
  if ( ! empty( $old_ops['simple_local_avatars_caps'] ) ) {
415
  update_option( 'simple_local_avatars', array( 'caps' => 1 ) );
416
  }
426
  'discussion',
427
  'avatars',
428
  array(
429
+ 'class' => 'simple-local-avatars',
430
+ 'key' => 'only',
431
+ 'desc' => __( 'Only allow local avatars (still uses Gravatar for default avatars)', 'simple-local-avatars' ),
432
  )
433
  );
434
  add_settings_field(
438
  'discussion',
439
  'avatars',
440
  array(
441
+ 'class' => 'simple-local-avatars',
442
+ 'key' => 'caps',
443
+ 'desc' => __( 'Only allow users with file upload capabilities to upload local avatars (Authors and above)', 'simple-local-avatars' ),
444
+ )
445
+ );
446
+
447
+ if ( is_multisite() ) {
448
+ add_settings_field(
449
+ 'simple-local-avatars-shared',
450
+ __( 'Shared network avatars', 'simple-local-avatars' ),
451
+ array( $this, 'avatar_settings_field' ),
452
+ 'discussion',
453
+ 'avatars',
454
+ array(
455
+ 'class' => 'simple-local-avatars',
456
+ 'key' => 'shared',
457
+ 'desc' => __( 'Uploaded avatars will be shared across the entire network, instead of being unique per site', 'simple-local-avatars' ),
458
+ 'default' => 1,
459
+ )
460
+ );
461
+ }
462
+
463
+ add_action( 'load-options-discussion.php', array( $this, 'load_discussion_page' ) );
464
+
465
+ // This is for network site settings.
466
+ if ( SLA_IS_NETWORK && is_network_admin() ) {
467
+ add_action( 'load-settings.php', array( $this, 'load_network_settings' ) );
468
+ }
469
+
470
+ add_settings_field(
471
+ 'simple-local-avatars-migration',
472
+ __( 'Migrate Other Local Avatars', 'simple-local-avatars' ),
473
+ array( $this, 'migrate_from_wp_user_avatar_settings_field' ),
474
+ 'discussion',
475
+ 'avatars'
476
+ );
477
+ add_settings_field(
478
+ 'simple-local-avatars-clear',
479
+ esc_html__( 'Clear local avatar cache', 'simple-local-avatars' ),
480
+ array( $this, 'avatar_settings_field' ),
481
+ 'discussion',
482
+ 'avatars',
483
+ array(
484
+ 'key' => 'clear_cache',
485
+ 'desc' => esc_html__( 'Clear cache of stored avatars', 'simple-local-avatars' ),
486
  )
487
  );
488
  }
489
 
490
+ /**
491
+ * Fire code on the Discussion page
492
+ */
493
+ public function load_discussion_page() {
494
+ add_action( 'admin_print_styles', array( $this, 'admin_print_styles' ) );
495
+ add_filter( 'admin_body_class', array( $this, 'admin_body_class' ) );
496
+ }
497
+
498
+ /**
499
+ * Load needed hooks to handle network settings
500
+ */
501
+ public function load_network_settings() {
502
+ $this->options = (array) get_site_option( 'simple_local_avatars', array() );
503
+
504
+ add_action( 'wpmu_options', array( $this, 'show_network_settings' ) );
505
+ add_action( 'update_wpmu_options', array( $this, 'save_network_settings' ) );
506
+ }
507
+
508
+ /**
509
+ * Show the network settings
510
+ */
511
+ public function show_network_settings() {
512
+ $mode = $this->get_network_mode();
513
+ ?>
514
+
515
+ <h2><?php esc_html_e( 'Simple Local Avatars Settings', 'simple-local-avatars' ); ?></h2>
516
+ <table id="simple-local-avatars" class="form-table">
517
+ <tr>
518
+ <th scope="row">
519
+ <?php esc_html_e( 'Mode', 'simple-local-avatars' ); ?>
520
+ </th>
521
+ <td>
522
+ <fieldset>
523
+ <legend class="screen-reader-text"><?php esc_html_e( 'Mode', 'simple-local-avatars' ); ?></legend>
524
+ <label><input name="simple_local_avatars[mode]" type="radio" id="sla-mode-default" value="default"<?php checked( $mode, 'default' ); ?> /> <?php esc_html_e( 'Default to the settings below when creating a new site', 'simple-local-avatars' ); ?></label><br/>
525
+ <label><input name="simple_local_avatars[mode]" type="radio" id="sla-mode-enforce" value="enforce"<?php checked( $mode, 'enforce' ); ?> /> <?php esc_html_e( 'Enforce the settings below across all sites', 'simple-local-avatars' ); ?></label><br/>
526
+ </fieldset>
527
+ </td>
528
+ </tr>
529
+ <tr>
530
+ <th scope="row">
531
+ <?php esc_html_e( 'Local avatars only', 'simple-local-avatars' ); ?>
532
+ </th>
533
+ <td>
534
+ <?php
535
+ $this->avatar_settings_field(
536
+ array(
537
+ 'key' => 'only',
538
+ 'desc' => __( 'Only allow local avatars (still uses Gravatar for default avatars) ', 'simple-local-avatars' ),
539
+ )
540
+ );
541
+ ?>
542
+ </td>
543
+ </tr>
544
+ <tr>
545
+ <th scope="row">
546
+ <?php esc_html_e( 'Local upload permissions', 'simple-local-avatars' ); ?>
547
+ </th>
548
+ <td>
549
+ <?php
550
+ $this->avatar_settings_field(
551
+ array(
552
+ 'key' => 'caps',
553
+ 'desc' => __( 'Only allow users with file upload capabilities to upload local avatars (Authors and above)', 'simple-local-avatars' ),
554
+ )
555
+ );
556
+ ?>
557
+ </td>
558
+ </tr>
559
+ <tr>
560
+ <th scope="row">
561
+ <?php esc_html_e( 'Shared network avatars', 'simple-local-avatars' ); ?>
562
+ </th>
563
+ <td>
564
+ <?php
565
+ $this->avatar_settings_field(
566
+ array(
567
+ 'key' => 'shared',
568
+ 'desc' => __( 'Uploaded avatars will be shared across the entire network, instead of being unique per site', 'simple-local-avatars' ),
569
+ 'default' => 1,
570
+ )
571
+ );
572
+ ?>
573
+ </td>
574
+ </tr>
575
+ </table>
576
+
577
+ <?php
578
+ }
579
+
580
+ /**
581
+ * Handle saving the network settings
582
+ */
583
+ public static function save_network_settings() {
584
+ $options = array(
585
+ 'caps',
586
+ 'mode',
587
+ 'only',
588
+ 'shared',
589
+ );
590
+ $sanitized = array();
591
+
592
+ foreach ( $options as $option_name ) {
593
+ if ( ! isset( $_POST['simple_local_avatars'][ $option_name ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
594
+ continue;
595
+ }
596
+
597
+ switch ( $option_name ) {
598
+ case 'mode':
599
+ update_site_option( 'simple_local_avatars_mode', sanitize_text_field( $_POST['simple_local_avatars'][ $option_name ] ) );
600
+ break;
601
+ default:
602
+ $sanitized[ $option_name ] = empty( $_POST['simple_local_avatars'][ $option_name ] ) ? 0 : 1;
603
+ }
604
+ }
605
+
606
+ update_site_option( 'simple_local_avatars', $sanitized );
607
+ }
608
+
609
  /**
610
  * Add scripts to the profile editing page
611
  *
612
  * @param string $hook_suffix Page hook
613
  */
614
  public function admin_enqueue_scripts( $hook_suffix ) {
615
+
616
+ /**
617
+ * Filter the admin screens where we enqueue our scripts.
618
+ *
619
+ * @param array $screens Array of admin screens.
620
+ * @param string $hook_suffix Page hook.
621
+ * @return array
622
+ */
623
+ $screens = apply_filters( 'simple_local_avatars_admin_enqueue_scripts', array( 'profile.php', 'user-edit.php', 'options-discussion.php' ), $hook_suffix );
624
+
625
+ if ( ! in_array( $hook_suffix, $screens, true ) ) {
626
  return;
627
  }
628
 
630
  wp_enqueue_media();
631
  }
632
 
633
+ $user_id = filter_input( INPUT_GET, 'user_id', FILTER_SANITIZE_NUMBER_INT );
634
+ $user_id = ( 'profile.php' === $hook_suffix ) ? get_current_user_id() : (int) $user_id;
635
 
636
  $this->remove_nonce = wp_create_nonce( 'remove_simple_local_avatar_nonce' );
637
 
638
+ wp_enqueue_script( 'simple-local-avatars', plugins_url( '', dirname( __FILE__ ) ) . '/dist/simple-local-avatars.js', array( 'jquery' ), SLA_VERSION, true );
 
639
  wp_localize_script(
640
  'simple-local-avatars',
641
  'i10n_SimpleLocalAvatars',
642
  array(
643
+ 'user_id' => $user_id,
644
+ 'insertMediaTitle' => __( 'Choose an Avatar', 'simple-local-avatars' ),
645
+ 'insertIntoPost' => __( 'Set as avatar', 'simple-local-avatars' ),
646
+ 'selectCrop' => __( 'Select avatar and Crop', 'simple-local-avatars' ),
647
+ 'deleteNonce' => $this->remove_nonce,
648
+ 'mediaNonce' => wp_create_nonce( 'assign_simple_local_avatar_nonce' ),
649
+ 'migrateFromWpUserAvatarNonce' => wp_create_nonce( 'migrate_from_wp_user_avatar_nonce' ),
650
+ 'migrateFromWpUserAvatarSuccess' => __( 'Number of avatars successfully migrated from WP User Avatar', 'simple-local-avatars' ),
651
+ 'migrateFromWpUserAvatarFailure' => __( 'No avatars were migrated from WP User Avatar.', 'simple-local-avatars' ),
652
+ 'migrateFromWpUserAvatarProgress' => __( 'Migration in progress.', 'simple-local-avatars' ),
653
  )
654
  );
655
  }
663
  public function sanitize_options( $input ) {
664
  $new_input['caps'] = empty( $input['caps'] ) ? 0 : 1;
665
  $new_input['only'] = empty( $input['only'] ) ? 0 : 1;
666
+
667
+ if ( is_multisite() ) {
668
+ $new_input['shared'] = empty( $input['shared'] ) ? 0 : 1;
669
+ }
670
+
671
  return $new_input;
672
  }
673
 
680
  $args = wp_parse_args(
681
  $args,
682
  array(
683
+ 'key' => '',
684
+ 'desc' => '',
685
+ 'default' => 0,
686
  )
687
  );
688
 
689
+ if ( ! isset( $this->options[ $args['key'] ] ) ) {
690
+ $this->options[ $args['key'] ] = $args['default'];
691
  }
692
 
693
+ if ( 'clear_cache' !== $args['key'] ) {
694
+ echo '
695
  <label for="simple-local-avatars-' . esc_attr( $args['key'] ) . '">
696
  <input type="checkbox" name="simple_local_avatars[' . esc_attr( $args['key'] ) . ']" id="simple-local-avatars-' . esc_attr( $args['key'] ) . '" value="1" ' . checked( $this->options[ $args['key'] ], 1, false ) . ' />
697
  ' . esc_html( $args['desc'] ) . '
698
  </label>
699
  ';
700
+ } else {
701
+ echo '<button id="clear_cache_btn" class="button delete" name="clear_cache_btn" >' . esc_html__( 'Clear cache', 'simple-local-avatars' ) . '</button><br/>';
702
+ echo '<span id="clear_cache_message" style="font-style:italic;font-size:14px;line-height:2;"></span>';
703
+ }
704
+
705
+ // Output warning if needed.
706
+ if (
707
+ SLA_IS_NETWORK // If network activated.
708
+ && $this->is_enforced() // And in enforce mode.
709
+ && 'shared' === $args['key'] // And we are displaying the last setting.
710
+ ) {
711
+ echo '
712
+ <div class="notice notice-warning inline">
713
+ <p><strong>' . esc_html__( 'Simple Local Avatar settings are currently enforced across all sites on the network.', 'simple-local-avatars' ) . '</strong></p>
714
+ </div>
715
+ ';
716
+ }
717
+ }
718
+
719
+ /**
720
+ * Settings field for migrating avatars away from WP User Avatar
721
+ */
722
+ public function migrate_from_wp_user_avatar_settings_field() {
723
+ printf(
724
+ '<p><button type="button" name="%1$s" id="%1$s" class="button button-secondary">%2$s</button></p><p class="%1$s-progress"></p>',
725
+ esc_attr( 'simple-local-avatars-migrate-from-wp-user-avatar' ),
726
+ esc_html__( 'Migrate avatars from WP User Avatar to Simple Local Avatars', 'simple-local-avatars' )
727
+ );
728
  }
729
 
730
  /**
733
  * @param object $profileuser User object
734
  */
735
  public function edit_user_profile( $profileuser ) {
736
+ ?>
737
+ <div id="simple-local-avatar-section">
738
+ <h3><?php esc_html_e( 'Avatar', 'simple-local-avatars' ); ?></h3>
739
+
740
+ <table class="form-table">
741
+ <tr class="upload-avatar-row">
742
+ <th scope="row"><label for="simple-local-avatar"><?php esc_html_e( 'Upload Avatar', 'simple-local-avatars' ); ?></label></th>
743
+ <td style="width: 50px;" id="simple-local-avatar-photo">
744
+ <?php
745
+ add_filter( 'pre_option_avatar_rating', '__return_null' ); // ignore ratings here
746
+ echo wp_kses_post( get_simple_local_avatar( $profileuser->ID ) );
747
+ remove_filter( 'pre_option_avatar_rating', '__return_null' );
748
+ ?>
749
+ </td>
750
+ <td>
751
+ <?php
752
+ $upload_rights = current_user_can( 'upload_files' );
753
+ if ( ! $upload_rights ) {
754
+ $upload_rights = empty( $this->options['caps'] );
755
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
756
 
757
+ if ( $upload_rights ) {
758
+ do_action( 'simple_local_avatar_notices' );
759
+ wp_nonce_field( 'simple_local_avatar_nonce', '_simple_local_avatar_nonce', false );
760
+ $remove_url = add_query_arg(
761
+ array(
762
+ 'action' => 'remove-simple-local-avatar',
763
+ 'user_id' => $profileuser->ID,
764
+ '_wpnonce' => $this->remove_nonce,
765
+ )
766
+ );
767
+ ?>
768
+ <?php
769
+ // if user is author and above hide the choose file option
770
+ // force them to use the WP Media Selector
771
+ if ( ! current_user_can( 'upload_files' ) ) {
772
+ ?>
773
+ <p style="display: inline-block; width: 26em;">
774
+ <span class="description"><?php esc_html_e( 'Choose an image from your computer:' ); ?></span><br />
775
+ <input type="file" name="simple-local-avatar" id="simple-local-avatar" class="standard-text" />
776
+ <span class="spinner" id="simple-local-avatar-spinner"></span>
777
+ </p>
778
+ <?php } ?>
779
+ <p>
780
+ <?php if ( current_user_can( 'upload_files' ) && did_action( 'wp_enqueue_media' ) ) : ?>
781
+ <a href="#" class="button hide-if-no-js" id="simple-local-avatar-media"><?php esc_html_e( 'Choose from Media Library', 'simple-local-avatars' ); ?></a> &nbsp;
782
+ <?php endif; ?>
783
+ <a href="<?php echo esc_url( $remove_url ); ?>" class="button item-delete submitdelete deletion" id="simple-local-avatar-remove" <?php echo empty( $profileuser->simple_local_avatar ) ? ' style="display:none;"' : ''; ?>>
784
+ <?php esc_html_e( 'Delete local avatar', 'simple-local-avatars' ); ?>
785
+ </a>
786
+ </p>
787
+ <?php
788
+ } else {
789
+ if ( empty( $profileuser->simple_local_avatar ) ) {
790
+ echo '<span class="description">' . esc_html__( 'No local avatar is set. Set up your avatar at Gravatar.com.', 'simple-local-avatars' ) . '</span>';
791
+ } else {
792
+ echo '<span class="description">' . esc_html__( 'You do not have media management permissions. To change your local avatar, contact the blog administrator.', 'simple-local-avatars' ) . '</span>';
793
+ }
794
+ }
795
+ ?>
796
+ </td>
797
+ </tr>
798
+ <tr class="ratings-row">
799
+ <th scope="row"><?php esc_html_e( 'Rating' ); ?></th>
800
+ <td colspan="2">
801
+ <fieldset id="simple-local-avatar-ratings" <?php disabled( empty( $profileuser->simple_local_avatar ) ); ?>>
802
+ <legend class="screen-reader-text"><span><?php esc_html_e( 'Rating' ); ?></span></legend>
803
+ <?php
804
+ $this->update_avatar_ratings();
805
+
806
+ if ( empty( $profileuser->simple_local_avatar_rating ) || ! array_key_exists( $profileuser->simple_local_avatar_rating, $this->avatar_ratings ) ) {
807
+ $profileuser->simple_local_avatar_rating = 'G';
808
+ }
809
+
810
+ foreach ( $this->avatar_ratings as $key => $rating ) :
811
+ echo "\n\t<label><input type='radio' name='simple_local_avatar_rating' value='" . esc_attr( $key ) . "' " . checked( $profileuser->simple_local_avatar_rating, $key, false ) . '/>' . esc_html( $rating ) . '</label><br />';
812
+ endforeach;
813
+ ?>
814
+ <p class="description"><?php esc_html_e( 'If the local avatar is inappropriate for this site, Gravatar will be attempted.', 'simple-local-avatars' ); ?></p>
815
+ </fieldset>
816
+ </td>
817
+ </tr>
818
+ </table>
819
+ </div>
820
+ <?php
821
  }
822
 
823
  /**
835
  */
836
  public function assign_new_user_avatar( $url_or_media_id, $user_id ) {
837
  // delete the old avatar
838
+ $this->avatar_delete( $user_id ); // delete old images if successful.
839
 
840
  $meta_value = array();
841
 
842
  // set the new avatar
843
+ if ( is_int( $url_or_media_id + 0 ) ) {
844
  $meta_value['media_id'] = $url_or_media_id;
845
  $url_or_media_id = wp_get_attachment_url( $url_or_media_id );
846
  }
847
 
848
+ $meta_value['full'] = $url_or_media_id;
849
+ $meta_value['blog_id'] = get_current_blog_id();
850
 
851
+ update_user_meta( $user_id, $this->user_key, $meta_value ); // save user information (overwriting old).
852
  }
853
 
854
  /**
869
  if ( false !== strpos( $_FILES['simple-local-avatar']['name'], '.php' ) ) {
870
  $this->avatar_upload_error = __( 'For security reasons, the extension ".php" cannot be in your file name.', 'simple-local-avatars' );
871
  add_action( 'user_profile_update_errors', array( $this, 'user_profile_update_errors' ) );
872
+
873
  return;
874
  }
875
 
902
  if ( is_wp_error( $avatar_id ) ) { // handle failures.
903
  $this->avatar_upload_error = '<strong>' . __( 'There was an error uploading the avatar:', 'simple-local-avatars' ) . '</strong> ' . esc_html( $avatar_id->get_error_message() );
904
  add_action( 'user_profile_update_errors', array( $this, 'user_profile_update_errors' ) );
905
+
906
  return;
907
  }
908
 
911
  endif;
912
 
913
  // Handle ratings
914
+ if ( isset( $avatar_id ) || get_user_meta( $user_id, $this->user_key, true ) ) {
915
  if ( empty( $_POST['simple_local_avatar_rating'] ) || ! array_key_exists( $_POST['simple_local_avatar_rating'], $this->avatar_ratings ) ) {
916
  $_POST['simple_local_avatar_rating'] = key( $this->avatar_ratings );
917
  }
918
 
919
+ update_user_meta( $user_id, $this->rating_key, $_POST['simple_local_avatar_rating'] );
920
  }
921
  }
922
 
944
  $this->avatar_delete( $user_id ); // delete old images if successful
945
 
946
  if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
947
+ echo wp_kses_post( get_simple_local_avatar( $user_id ) );
948
  }
949
  }
950
 
970
  $this->assign_new_user_avatar( $media_id, $user_id );
971
  }
972
 
973
+ echo wp_kses_post( get_simple_local_avatar( $user_id ) );
974
 
975
  die;
976
  }
981
  * @param int $user_id User ID.
982
  */
983
  public function avatar_delete( $user_id ) {
984
+ $old_avatars = (array) get_user_meta( $user_id, $this->user_key, true );
985
 
986
  if ( empty( $old_avatars ) ) {
987
  return;
1004
  }
1005
  }
1006
 
1007
+ delete_user_meta( $user_id, $this->user_key );
1008
+ delete_user_meta( $user_id, $this->rating_key );
1009
  }
1010
 
1011
  /**
1018
  */
1019
  public function unique_filename_callback( $dir, $name, $ext ) {
1020
  $user = get_user_by( 'id', (int) $this->user_id_being_edited );
1021
+ $name = $base_name = sanitize_file_name( $user->display_name . '_avatar_' . time() ); //phpcs:ignore
1022
 
1023
  // ensure no conflicts with existing file names
1024
  $number = 1;
1025
  while ( file_exists( $dir . "/$name$ext" ) ) {
1026
  $name = $base_name . '_' . $number;
1027
+ $number ++;
1028
  }
1029
 
1030
  return $name . $ext;
1063
  * @param object $user User object
1064
  */
1065
  public function get_avatar_rest( $user ) {
1066
+ $local_avatar = get_user_meta( $user['id'], $this->user_key, true );
1067
  if ( empty( $local_avatar ) ) {
1068
  return;
1069
  }
1070
+
1071
  return $local_avatar;
1072
  }
1073
 
1084
  public function set_avatar_rest( $input, $user ) {
1085
  $this->assign_new_user_avatar( $input['media_id'], $user->ID );
1086
  }
1087
+
1088
+ /**
1089
+ * Short-circuit filter the `simple_local_avatars` option to match network if necessary
1090
+ *
1091
+ * @param bool $value Value of `simple_local_avatars` option, typically false.
1092
+ *
1093
+ * @return array
1094
+ */
1095
+ public function pre_option_simple_local_avatars( $value ) {
1096
+ if ( SLA_IS_NETWORK && 'enforce' === $this->get_network_mode() ) {
1097
+ $value = get_site_option( 'simple_local_avatars', array() );
1098
+ }
1099
+
1100
+ return $value;
1101
+ }
1102
+
1103
+ /**
1104
+ * Set plugin defaults for a new site
1105
+ *
1106
+ * @param int $blog_id Blog ID.
1107
+ */
1108
+ public function set_defaults( $blog_id ) {
1109
+ if ( 'enforce' === $this->get_network_mode() ) {
1110
+ return;
1111
+ }
1112
+
1113
+ switch_to_blog( $blog_id );
1114
+ update_option( 'simple_local_avatars', $this->sanitize_options( $this->options ) );
1115
+ restore_current_blog();
1116
+ }
1117
+
1118
+ /**
1119
+ * Add some basic styling on the Discussion page
1120
+ */
1121
+ public function admin_print_styles() {
1122
+ ?>
1123
+ <style>
1124
+ .sla-enforced .simple-local-avatars th,
1125
+ .sla-enforced .simple-local-avatars label {
1126
+ opacity: 0.5;
1127
+ pointer-events: none;
1128
+ }
1129
+
1130
+ .sla-enforced .simple-local-avatars .notice {
1131
+ margin-top: 20px;
1132
+ }
1133
+
1134
+ @media screen and (min-width: 783px) {
1135
+ .sla-enforced .simple-local-avatars .notice {
1136
+ left: -220px;
1137
+ position: relative;
1138
+ }
1139
+ }
1140
+ </style>
1141
+ <?php
1142
+ }
1143
+
1144
+ /**
1145
+ * Adds admin body classes to the Discussion options screen
1146
+ *
1147
+ * @param string $classes Space-separated list of classes to apply to the body element.
1148
+ *
1149
+ * @return string
1150
+ */
1151
+ public function admin_body_class( $classes ) {
1152
+ if ( $this->is_enforced() ) {
1153
+ $classes .= ' sla-enforced';
1154
+ }
1155
+
1156
+ return $classes;
1157
+ }
1158
+
1159
+ /**
1160
+ * Overwriting existing avatar_ratings so this can be called just before the rating strings would be used so that
1161
+ * translations will work correctly.
1162
+ * Default text-domain because the strings have already been translated
1163
+ */
1164
+ private function update_avatar_ratings() {
1165
+ $this->avatar_ratings = array(
1166
+ 'G' => __( 'G &#8212; Suitable for all audiences' ),
1167
+ 'PG' => __( 'PG &#8212; Possibly offensive, usually for audiences 13 and above' ),
1168
+ 'R' => __( 'R &#8212; Intended for adult audiences above 17' ),
1169
+ 'X' => __( 'X &#8212; Even more mature than above' ),
1170
+ );
1171
+ }
1172
+
1173
+ /**
1174
+ * Load script required for handling any actions.
1175
+ */
1176
+ public function admin_scripts() {
1177
+ wp_enqueue_script(
1178
+ 'sla_admin',
1179
+ SLA_PLUGIN_URL . 'assets/js/admin.js',
1180
+ [ 'jquery' ],
1181
+ SLA_VERSION,
1182
+ true
1183
+ );
1184
+
1185
+ wp_localize_script(
1186
+ 'sla_admin',
1187
+ 'slaAdmin',
1188
+ [
1189
+ 'nonce' => wp_create_nonce( 'sla_clear_cache_nonce' ),
1190
+ 'error' => esc_html__( 'Something went wrong while clearing cache, please try again.', 'simple-local-avatars' ),
1191
+ ]
1192
+ );
1193
+ }
1194
+
1195
+ /**
1196
+ * Clear user cache.
1197
+ */
1198
+ public function sla_clear_user_cache() {
1199
+ check_ajax_referer( 'sla_clear_cache_nonce', 'nonce' );
1200
+ $step = isset( $_REQUEST['step'] ) ? intval( $_REQUEST['step'] ) : 1;
1201
+
1202
+ // Setup defaults.
1203
+ $users_per_page = 50;
1204
+ $offset = ( $step - 1 ) * $users_per_page;
1205
+
1206
+ $users_query = new \WP_User_Query(
1207
+ array(
1208
+ 'fields' => array( 'ID' ),
1209
+ 'number' => $users_per_page,
1210
+ 'offset' => $offset,
1211
+ )
1212
+ );
1213
+
1214
+ // Total users in the site.
1215
+ $total_users = $users_query->get_total();
1216
+
1217
+ // Get the users.
1218
+ $users = $users_query->get_results();
1219
+
1220
+ if ( ! empty( $users ) ) {
1221
+ foreach ( $users as $user ) {
1222
+ $user_id = $user->ID;
1223
+ $local_avatars = get_user_meta( $user_id, 'simple_local_avatar', true );
1224
+ $media_id = isset( $local_avatars['media_id'] ) ? $local_avatars['media_id'] : '';
1225
+ $this->clear_user_avatar_cache( $local_avatars, $user_id, $media_id );
1226
+ }
1227
+
1228
+ wp_send_json_success(
1229
+ array(
1230
+ 'step' => $step + 1,
1231
+ 'message' => sprintf(
1232
+ /* translators: 1: Offset, 2: Total users */
1233
+ esc_html__( 'Processing %1$s/%2$s users...', 'simple-local-avatars' ),
1234
+ $offset,
1235
+ $total_users
1236
+ ),
1237
+ )
1238
+ );
1239
+ }
1240
+
1241
+ wp_send_json_success(
1242
+ array(
1243
+ 'step' => 'done',
1244
+ 'message' => sprintf(
1245
+ /* translators: %s Total users */
1246
+ esc_html__( 'Completed clearing cache for all %s user(s) avatars.', 'simple-local-avatars' ),
1247
+ $total_users
1248
+ ),
1249
+ )
1250
+ );
1251
+ }
1252
+
1253
+ /**
1254
+ * Clear avatar cache for given user.
1255
+ *
1256
+ * @param array $local_avatars Local avatars.
1257
+ * @param int $user_id User ID.
1258
+ * @param mixed $media_id Media ID.
1259
+ */
1260
+ private function clear_user_avatar_cache( $local_avatars, $user_id, $media_id ) {
1261
+ if ( ! empty( $media_id ) ) {
1262
+ $file_name_data = pathinfo( wp_get_original_image_path( $media_id ) );
1263
+ $file_dir_name = $file_name_data['dirname'];
1264
+ $file_name = $file_name_data['filename'];
1265
+ $file_ext = $file_name_data['extension'];
1266
+ foreach ( $local_avatars as $local_avatars_key => $local_avatar_value ) {
1267
+ if ( ! in_array( $local_avatars_key, [ 'media_id', 'full' ], true ) ) {
1268
+ $file_size_path = sprintf( '%1$s/%2$s-%3$sx%3$s.%4$s', $file_dir_name, $file_name, $local_avatars_key, $file_ext );
1269
+ if ( ! file_exists( $file_size_path ) ) {
1270
+ unset( $local_avatars[ $local_avatars_key ] );
1271
+ }
1272
+ }
1273
+ }
1274
+
1275
+ // Update meta, remove sizes that don't exist.
1276
+ update_user_meta( $user_id, 'simple_local_avatar', $local_avatars );
1277
+ }
1278
+ }
1279
+
1280
+ /**
1281
+ * Migrate the user's avatar data from WP User Avatar/ProfilePress
1282
+ *
1283
+ * This function creates a new option in the wp_options table to store the processed user IDs
1284
+ * so that we can run this command multiple times without processing the same user over and over again.
1285
+ *
1286
+ * Credit to Philip John for the Gist
1287
+ *
1288
+ * @see https://gist.github.com/philipjohn/822d3521a95481f6ad7e118a7106fbc7
1289
+ *
1290
+ * @return int
1291
+ */
1292
+ public function migrate_from_wp_user_avatar() {
1293
+
1294
+ global $wpdb;
1295
+
1296
+ $count = 0;
1297
+
1298
+ // Support single site and multisite installs.
1299
+ // Use WordPress function if running multisite.
1300
+ // Create generic class if running single site.
1301
+ if ( is_multisite() ) {
1302
+ $sites = get_sites();
1303
+ } else {
1304
+ $site = new stdClass();
1305
+ $site->blog_id = 1;
1306
+ $sites = array( $site );
1307
+ }
1308
+
1309
+ // Bail early if we don't find sites.
1310
+ if ( empty( $sites ) ) {
1311
+ return $count;
1312
+ }
1313
+
1314
+ foreach ( $sites as $site ) {
1315
+ // Get the blog ID to use in the meta key and user query.
1316
+ $blog_id = isset( $site->blog_id ) ? $site->blog_id : 1;
1317
+
1318
+ // Get the name of the meta key for WP User Avatar.
1319
+ $meta_key = $wpdb->get_blog_prefix( $blog_id ) . 'user_avatar';
1320
+
1321
+ // Get processed users from database.
1322
+ $migrations = get_option( 'simple_local_avatars_migrations', array() );
1323
+ $processed_users = isset( $migrations['wp_user_avatar'] ) ? $migrations['wp_user_avatar'] : array();
1324
+
1325
+ // Get all users that have a local avatar.
1326
+ $users = get_users(
1327
+ array(
1328
+ 'blog_id' => $blog_id,
1329
+ 'exclude' => $processed_users,
1330
+ 'meta_key' => $meta_key,
1331
+ 'meta_compare' => 'EXISTS',
1332
+ )
1333
+ );
1334
+
1335
+ // Bail early if we don't find users.
1336
+ if ( empty( $users ) ) {
1337
+ continue;
1338
+ }
1339
+
1340
+ foreach ( $users as $user ) {
1341
+ // Get the existing avatar media ID.
1342
+ $avatar_id = get_user_meta( $user->ID, $meta_key, true );
1343
+
1344
+ // Attach the user and media to Simple Local Avatars.
1345
+ $sla = new Simple_Local_Avatars();
1346
+ $sla->assign_new_user_avatar( (int) $avatar_id, $user->ID );
1347
+
1348
+ // Check that it worked.
1349
+ $is_migrated = get_user_meta( $user->ID, 'simple_local_avatar', true );
1350
+
1351
+ if ( ! empty( $is_migrated ) ) {
1352
+ // Build array of user IDs.
1353
+ $migrations['wp_user_avatar'][] = $user->ID;
1354
+
1355
+ // Record the user IDs so we don't process a second time.
1356
+ $is_saved = update_option( 'simple_local_avatars_migrations', $migrations );
1357
+
1358
+ // Record how many avatars we migrate to be used in our messaging.
1359
+ if ( $is_saved ) {
1360
+ $count ++;
1361
+ }
1362
+ }
1363
+ }
1364
+ }
1365
+
1366
+ return $count;
1367
+
1368
+ }
1369
+
1370
+ /**
1371
+ * Migrate the user's avatar data away from WP User Avatar/ProfilePress via the dashboard.
1372
+ *
1373
+ * Sends the number of avatars processed back to the AJAX response before stopping execution.
1374
+ *
1375
+ * @return void
1376
+ */
1377
+ public function ajax_migrate_from_wp_user_avatar() {
1378
+ // Bail early if nonce is not available.
1379
+ if ( empty( sanitize_text_field( $_POST['migrateFromWpUserAvatarNonce'] ) ) ) {
1380
+ die;
1381
+ }
1382
+
1383
+ // Bail early if nonce is invalid.
1384
+ if ( ! wp_verify_nonce( sanitize_text_field( $_POST['migrateFromWpUserAvatarNonce'] ), 'migrate_from_wp_user_avatar_nonce' ) ) {
1385
+ die();
1386
+ }
1387
+
1388
+ // Run the migration script and store the number of avatars processed.
1389
+ $count = $this->migrate_from_wp_user_avatar();
1390
+
1391
+ // Create the array we send back to javascript here.
1392
+ $array_we_send_back = array( 'count' => $count );
1393
+
1394
+ // Make sure to json encode the output because that's what it is expecting.
1395
+ echo wp_json_encode( $array_we_send_back );
1396
+
1397
+ // Make sure you die when finished doing ajax output.
1398
+ wp_die();
1399
+
1400
+ }
1401
+
1402
+ /**
1403
+ * Migrate the user's avatar data from WP User Avatar/ProfilePress via the command line.
1404
+ *
1405
+ * ## OPTIONS
1406
+ *
1407
+ * [--yes]
1408
+ * : Skips the confirmations (for automated systems).
1409
+ *
1410
+ * ## EXAMPLES
1411
+ *
1412
+ * $ wp simple-local-avatars migrate wp-user-avatar
1413
+ * Success: Number of avatars successfully migrated from WP User Avatar: 5
1414
+ *
1415
+ * @param array $args The arguments.
1416
+ * @param array $assoc_args The associative arguments.
1417
+ *
1418
+ * @return void
1419
+ */
1420
+ public function wp_cli_migrate_from_wp_user_avatar( $args, $assoc_args ) {
1421
+
1422
+ // Argument --yes to prevent confirmation (for automated systems).
1423
+ if ( ! isset( $assoc_args['yes'] ) ) {
1424
+ WP_CLI::confirm( esc_html__( 'Do you want to migrate avatars from WP User Avatar?', 'simple-local-avatars' ) );
1425
+ }
1426
+
1427
+ // Run the migration script and store the number of avatars processed.
1428
+ $count = $this->migrate_from_wp_user_avatar();
1429
+
1430
+ // Error out if we don't process any avatars.
1431
+ if ( 0 === absint( $count ) ) {
1432
+ WP_CLI::error( esc_html__( 'No avatars were migrated from WP User Avatar.', 'simple-local-avatars' ) );
1433
+ }
1434
+
1435
+ WP_CLI::success(
1436
+ sprintf(
1437
+ '%s: %s',
1438
+ esc_html__( 'Number of avatars successfully migrated from WP User Avatar', 'simple-local-avatars' ),
1439
+ esc_html( $count )
1440
+ )
1441
+ );
1442
+ }
1443
  }
readme.txt CHANGED
@@ -3,9 +3,9 @@ Contributors: jakemgold, 10up, thinkoomph
3
  Donate link: https://10up.com/plugins/simple-local-avatars-wordpress/
4
  Tags: avatar, gravatar, user photos, users, profile
5
  Requires at least: 4.6
6
- Tested up to: 5.8
7
- Requires PHP: 5.3
8
- Stable tag: 2.2.0
9
  License: GPLv2 or later
10
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
11
 
@@ -41,33 +41,53 @@ You can also use `get_simple_local_avatar()` (with the same arguments) to retrei
41
 
42
  == Changelog ==
43
 
44
- = 2.2.0 =
45
- * **Added:** `$args` parameter to `get_simple_local_avatar` function (props [@dinhtungdu](https://profiles.wordpress.org/dinhtungdu/), [@heyjones](https://github.com/heyjones), [@dkotter](https://profiles.wordpress.org/dkotter/), [@sumnercreations](https://github.com/sumnercreations), [@dshanske](https://profiles.wordpress.org/dshanske/))
46
- * **Added:** `Simple_Local_Avatars::get_avatar_data()`, `Simple_Local_Avatars::get_simple_local_avatar_url()`, and `Simple_Local_Avatars::get_default_avatar_url()` methods (props [@dinhtungdu](https://profiles.wordpress.org/dinhtungdu/), [@heyjones](https://github.com/heyjones), [@dkotter](https://profiles.wordpress.org/dkotter/), [@sumnercreations](https://github.com/sumnercreations), [@dshanske](https://profiles.wordpress.org/dshanske/))
47
- * **Added:** Ability to retrieve avatar with `WP_Post` object (props [@oscarssanchez](https://profiles.wordpress.org/oscarssanchez), [@blobaugh](https://profiles.wordpress.org/blobaugh))
48
- * **Added:** class and ID to Avatar section on Profile Page to allow easier styling (props [@dinhtungdu](https://profiles.wordpress.org/dinhtungdu/))
49
- * **Added:** [WP Acceptance](https://github.com/10up/wpacceptance/) test coverage (props [@dinhtungdu](https://profiles.wordpress.org/dinhtungdu/))
50
- * **Changed:** Switched to `pre_get_avatar_data` filter (props [@dinhtungdu](https://profiles.wordpress.org/dinhtungdu/), [@heyjones](https://github.com/heyjones), [@dkotter](https://profiles.wordpress.org/dkotter/), [@sumnercreations](https://github.com/sumnercreations), [@dshanske](https://profiles.wordpress.org/dshanske/))
51
- * **Changed:** `assign_new_user_avatar` function to public (props [@tripflex](https://profiles.wordpress.org/tripflex/))
52
- * **Changed:** Split the main class into its own file, added unit tests, and set up testing GitHub action (props [@dinhtungdu](https://profiles.wordpress.org/dinhtungdu/), [@helen](https://profiles.wordpress.org/helen/), [@stevegrunwell](https://profiles.wordpress.org/stevegrunwell/))
53
- * **Changed:** New plugin banner and icon (props [@JackieKjome](https://profiles.wordpress.org/jackiekjome/))
54
- * **Changed:** Bump WordPress version "tested up to" 5.5 (props [@Waka867](https://github.com/Waka867), [@tmoorewp](https://profiles.wordpress.org/tmoorewp), [@jeffpaul](https://profiles.wordpress.org/jeffpaul), [@dinhtungdu](https://profiles.wordpress.org/dinhtungdu/))
55
- * **Changed:** GitHub Actions from HCL to YAML workflow syntax (props [@jeffpaul](https://profiles.wordpress.org/jeffpaul))
56
- * **Changed:** Documentation updates (props [@jeffpaul](https://profiles.wordpress.org/jeffpaul))
57
- * **Fixed:** Initialize `Simple_Local_Avatars` on the `$simple_local_avatars` global, enabling bundling plugin with composer (props [@pauldewouters](https://profiles.wordpress.org/pauldewouters/), [@adamsilverstein](https://profiles.wordpress.org/adamsilverstein))
58
- * **Removed:** `get_avatar` function that overrides the core function (props [@dinhtungdu](https://profiles.wordpress.org/dinhtungdu/), [@heyjones](https://github.com/heyjones), [@dkotter](https://profiles.wordpress.org/dkotter/), [@sumnercreations](https://github.com/sumnercreations), [@dshanske](https://profiles.wordpress.org/dshanske/))
59
-
60
- = 2.1.1 =
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
61
  * Fixed: Do not delete avatars just because they don't exist on the local filesystem. This was occasionally dumping avatars when WordPress uploads were stored elsewhere, e.g. a cloud service.
62
 
63
- = 2.1 =
64
  * *New:* All avatar uploads now go into the media library. Don't worry - users without the ability to upload files cannot otherwise see the contents of your media library. This allows local avatars to respect other functionality your site may have around uploaded images, such as external hosting.
65
  * *New:* REST API support for getting and updating.
66
  * *New:* Use .org language packs rather than bundling translations.
67
  * *Fixed:* Avoid an `ArgumentCountError`.
68
  * *Fixed:* A couple of internationalization issues.
69
 
70
- = 2.0 =
71
  * Choose or upload an avatar from the media library (for users with appropriate capabilities)!
72
  * Local avatars are rated for appropriateness, just like Gravatar
73
  * A new setting under Discussion enables administrators to turn off Gravatar (only use local avatars)
@@ -80,49 +100,52 @@ You can also use `get_simple_local_avatar()` (with the same arguments) to retrei
80
  * Hungarian translation added (needs further updating again with new version)
81
  * Assorted refactoring / improvements under the hood
82
 
83
- = 1.3.1 =
84
  * Brazilian Portuguese and Belarusian translations
85
  * Bug fixes (most notably correct naming of image files based on user display name)
86
  * Optimization for WordPress 3.2 / 3.3 (substitutes deprecated function)
87
 
88
- = 1.3 =
89
  * Avatar file name saved as "user-display-name_avatar" (or other image extension)
90
  * Russian localization added
91
  * Assorted minor code optimizations
92
 
93
- = 1.2.4 =
94
  * Support for front end avatar uploads (e.g. Theme My Profile)
95
 
96
- = 1.2.3 =
97
  * Russian localization
98
 
99
- = 1.2.2 =
100
  * Fix for avatars uploaded pre-1.2.1 having a broken path after upgrade
101
 
102
- = 1.2.1 =
103
  * French localization
104
  * Simplify uninstall code
105
 
106
- = 1.2 =
107
  * Fix path issues on some IIS servers (resulting in missing avatar images)
108
  * Fix rare uninstall issues related to deleted avatars
109
  * Spanish localization
110
  * Other minor under the hood optimizations
111
 
112
- = 1.1.3 =
113
  * Properly deletes old avatars upon changing avatar
114
  * Fixes "foreach" warning in debug mode when updating avatar image
115
 
116
- = 1.1.2 =
117
  * Norwegian localization
118
 
119
- = 1.1.1 =
120
  * Italian localization
121
 
122
- = 1.1 =
123
  * All users (regardless of capabilities) can upload avatars by default. To limit avatar uploading to users with upload files capabilities (Authors and above), check the applicable option under Settings > Discussion. This was the default behavior in 1.0.
124
  * Localization support; German included
125
 
 
 
 
126
  == Upgrade Notice ==
127
 
128
  = 2.1 =
@@ -132,4 +155,4 @@ You can also use `get_simple_local_avatar()` (with the same arguments) to retrei
132
  Upgraded to take advantage of *WordPress 3.5 and newer*. Does not support older versions! This has also *not* been tested with front end profile plug-ins - feedback welcome. Note that several language strings have been added or modified - revised translations would be welcome!
133
 
134
  = 1.3.1 =
135
- Like WordPress 3.2, now *REQUIRES* PHP 5.2 or newer.
3
  Donate link: https://10up.com/plugins/simple-local-avatars-wordpress/
4
  Tags: avatar, gravatar, user photos, users, profile
5
  Requires at least: 4.6
6
+ Tested up to: 6.0
7
+ Requires PHP: 5.6
8
+ Stable tag: 2.3.0
9
  License: GPLv2 or later
10
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
11
 
41
 
42
  == Changelog ==
43
 
44
+ = 2.3.0 =
45
+ * **Added:** Crop screen (props [@jeffpaul](https://github.com/jeffpaul), [@helen](https://github.com/helen), [@ajmaurya99](https://github.com/ajmaurya99), [@Antonio-Lagun](https://github.com/Antonio-Lagun), [@faisal-alvi](https://github.com/faisal-alvi)).
46
+ * **Added:** Avatar preview for Subscribers (props [@ankitguptaindia](https://github.com/ankitguptaindia), [@dinhtungdu](https://github.com/dinhtungdu), [@dkotter](https://github.com/dkotter)).
47
+ * **Added:** More robust multisite support and shared avatar setting (props [@adamsilverstein](https://github.com/adamsilverstein), [@helen](https://github.com/helen), [@jeffpaul](https://github.com/jeffpaul), [@dkotter](https://github.com/dkotter), [@faisal-alvi](https://github.com/faisal-alvi), [@holle75](https://github.com/holle75)).
48
+ * **Added:** Settings link to plugin action links (props [@rahulsprajapati](https://github.com/rahulsprajapati), [@jeffpaul](https://github.com/jeffpaul), [@iamdharmesh](https://github.com/iamdharmesh)).
49
+ * **Added:** Dashboard setting and WP-CLI command to migrate avatars from WP User Avatars (props [@jeffpaul](https://github.com/jeffpaul), [@claytoncollie](https://github.com/claytoncollie), [@helen](https://github.com/helen), [@faisal-alvi](https://github.com/faisal-alvi)).
50
+ * **Added:** Option to clear cache of user meta to remove image sizes that do not exist (props [@jeffpaul](https://github.com/jeffpaul), [@ituk](https://github.com/ituk), [@dinhtungdu](https://github.com/dinhtungdu), [@sparkbold](https://github.com/sparkbold), [@thrijith](https://github.com/thrijith)).
51
+ * **Added:** Package file (props [@faisal-alvi](https://github.com/faisal-alvi), [@jeffpaul](https://github.com/jeffpaul), [@claytoncollie](https://github.com/claytoncollie), [@cadic](https://github.com/cadic)).
52
+ * **Added:** PHP Unit Tests (props [@faisal-alvi](https://github.com/faisal-alvi), [@iamdharmesh](https://github.com/iamdharmesh)).
53
+ * **Added:** "No Response" GitHub Action (props [@jeffpaul](https://github.com/jeffpaul)).
54
+ * **Changed:** Bump WordPress "tested up to" version to 5.9 (props [@jeffpaul](https://github.com/jeffpaul), [@ankitguptaindia](https://github.com/ankitguptaindia), [@dinhtungdu](https://github.com/dinhtungdu), [@phpbits](https://github.com/phpbits)).
55
+ * **Changed:** - Bump WordPress "tested up to" version to 6.0 (props [@ajmaurya99](https://github.com/ajmaurya99) via [#110](https://github.com/10up/simple-local-avatars/pull/110)).
56
+ * **Changed:** Format admin script (props [@thrijith](https://github.com/thrijith), [@dinhtungdu](https://github.com/dinhtungdu)).
57
+ * **Fixed:** Media ID as string in REST API (props [@diodoe](https://github.com/), [@dinhtungdu](https://github.com/dinhtungdu), [@dkotter](https://github.com/dkotter)).
58
+ * **Fixed:** Avatar rating text is not translated properly if a user has a custom language Set (props [@ActuallyConnor](https://github.com/ActuallyConnor), [@faisal-alvi](https://github.com/faisal-alvi)).
59
+ * **Security:** PHP 8 compatibility (props [@faisal-alvi](https://github.com/faisal-alvi), [@dkotter](https://github.com/dkotter), [@Sidsector9](https://github.com/Sidsector9)).
60
+ * **Security:** Bump `rmccue/requests` from 1.7.0 to 1.8.0 (props [dependabot@](https://github.com/dependabot)).
61
+ * **Security:** Bump `nanoid` from 3.1.28 to 3.2.0 (props [dependabot@](https://github.com/dependabot)).
62
+ * **Security:** Bump `minimist` from 1.2.5 to 1.2.6 (props [dependabot@](https://github.com/dependabot)).
63
+
64
+ = 2.2.0 - 2020-10-27 =
65
+ * **Added:** `$args` parameter to `get_simple_local_avatar` function (props [@dinhtungdu](https://profiles.wordpress.org/dinhtungdu/), [@heyjones](https://github.com/heyjones), [@dkotter](https://profiles.wordpress.org/dkotter/), [@sumnercreations](https://github.com/sumnercreations), [@dshanske](https://profiles.wordpress.org/dshanske/)).
66
+ * **Added:** `Simple_Local_Avatars::get_avatar_data()`, `Simple_Local_Avatars::get_simple_local_avatar_url()`, and `Simple_Local_Avatars::get_default_avatar_url()` methods (props [@dinhtungdu](https://profiles.wordpress.org/dinhtungdu/), [@heyjones](https://github.com/heyjones), [@dkotter](https://profiles.wordpress.org/dkotter/), [@sumnercreations](https://github.com/sumnercreations), [@dshanske](https://profiles.wordpress.org/dshanske/)).
67
+ * **Added:** Ability to retrieve avatar with `WP_Post` object (props [@oscarssanchez](https://profiles.wordpress.org/oscarssanchez), [@blobaugh](https://profiles.wordpress.org/blobaugh)).
68
+ * **Added:** class and ID to Avatar section on Profile Page to allow easier styling (props [@dinhtungdu](https://profiles.wordpress.org/dinhtungdu/)).
69
+ * **Added:** [WP Acceptance](https://github.com/10up/wpacceptance/) test coverage (props [@dinhtungdu](https://profiles.wordpress.org/dinhtungdu/)).
70
+ * **Changed:** Switched to `pre_get_avatar_data` filter (props [@dinhtungdu](https://profiles.wordpress.org/dinhtungdu/), [@heyjones](https://github.com/heyjones), [@dkotter](https://profiles.wordpress.org/dkotter/), [@sumnercreations](https://github.com/sumnercreations), [@dshanske](https://profiles.wordpress.org/dshanske/)).
71
+ * **Changed:** `assign_new_user_avatar` function to public (props [@tripflex](https://profiles.wordpress.org/tripflex/)).
72
+ * **Changed:** Split the main class into its own file, added unit tests, and set up testing GitHub action (props [@dinhtungdu](https://profiles.wordpress.org/dinhtungdu/), [@helen](https://profiles.wordpress.org/helen/), [@stevegrunwell](https://profiles.wordpress.org/stevegrunwell/)).
73
+ * **Changed:** New plugin banner and icon (props [@JackieKjome](https://profiles.wordpress.org/jackiekjome/)).
74
+ * **Changed:** Bump WordPress version "tested up to" 5.5 (props [@Waka867](https://github.com/Waka867), [@tmoorewp](https://profiles.wordpress.org/tmoorewp), [@jeffpaul](https://profiles.wordpress.org/jeffpaul), [@dinhtungdu](https://profiles.wordpress.org/dinhtungdu/)).
75
+ * **Changed:** GitHub Actions from HCL to YAML workflow syntax (props [@jeffpaul](https://profiles.wordpress.org/jeffpaul)).
76
+ * **Changed:** Documentation updates (props [@jeffpaul](https://profiles.wordpress.org/jeffpaul)).
77
+ * **Fixed:** Initialize `Simple_Local_Avatars` on the `$simple_local_avatars` global, enabling bundling plugin with composer (props [@pauldewouters](https://profiles.wordpress.org/pauldewouters/), [@adamsilverstein](https://profiles.wordpress.org/adamsilverstein)).
78
+ * **Removed:** `get_avatar` function that overrides the core function (props [@dinhtungdu](https://profiles.wordpress.org/dinhtungdu/), [@heyjones](https://github.com/heyjones), [@dkotter](https://profiles.wordpress.org/dkotter/), [@sumnercreations](https://github.com/sumnercreations), [@dshanske](https://profiles.wordpress.org/dshanske/)).
79
+
80
+ = 2.1.1 - 2019-05-07 =
81
  * Fixed: Do not delete avatars just because they don't exist on the local filesystem. This was occasionally dumping avatars when WordPress uploads were stored elsewhere, e.g. a cloud service.
82
 
83
+ = 2.1 - 2018-10-24 =
84
  * *New:* All avatar uploads now go into the media library. Don't worry - users without the ability to upload files cannot otherwise see the contents of your media library. This allows local avatars to respect other functionality your site may have around uploaded images, such as external hosting.
85
  * *New:* REST API support for getting and updating.
86
  * *New:* Use .org language packs rather than bundling translations.
87
  * *Fixed:* Avoid an `ArgumentCountError`.
88
  * *Fixed:* A couple of internationalization issues.
89
 
90
+ = 2.0 - 2013-06-02 =
91
  * Choose or upload an avatar from the media library (for users with appropriate capabilities)!
92
  * Local avatars are rated for appropriateness, just like Gravatar
93
  * A new setting under Discussion enables administrators to turn off Gravatar (only use local avatars)
100
  * Hungarian translation added (needs further updating again with new version)
101
  * Assorted refactoring / improvements under the hood
102
 
103
+ = 1.3.1 - 2011-12-29 =
104
  * Brazilian Portuguese and Belarusian translations
105
  * Bug fixes (most notably correct naming of image files based on user display name)
106
  * Optimization for WordPress 3.2 / 3.3 (substitutes deprecated function)
107
 
108
+ = 1.3 - 2011-09-22 =
109
  * Avatar file name saved as "user-display-name_avatar" (or other image extension)
110
  * Russian localization added
111
  * Assorted minor code optimizations
112
 
113
+ = 1.2.4 - 2011-07-02 =
114
  * Support for front end avatar uploads (e.g. Theme My Profile)
115
 
116
+ = 1.2.3 - 2011-04-04 =
117
  * Russian localization
118
 
119
+ = 1.2.2 - 2011-03-25 =
120
  * Fix for avatars uploaded pre-1.2.1 having a broken path after upgrade
121
 
122
+ = 1.2.1 - 2011-01-26 =
123
  * French localization
124
  * Simplify uninstall code
125
 
126
+ = 1.2 - 2011-01-26 =
127
  * Fix path issues on some IIS servers (resulting in missing avatar images)
128
  * Fix rare uninstall issues related to deleted avatars
129
  * Spanish localization
130
  * Other minor under the hood optimizations
131
 
132
+ = 1.1.3 - 2011-01-20 =
133
  * Properly deletes old avatars upon changing avatar
134
  * Fixes "foreach" warning in debug mode when updating avatar image
135
 
136
+ = 1.1.2 - 2011-01-18 =
137
  * Norwegian localization
138
 
139
+ = 1.1.1 - 2011-01-18 =
140
  * Italian localization
141
 
142
+ = 1.1 - 2011-01-18 =
143
  * All users (regardless of capabilities) can upload avatars by default. To limit avatar uploading to users with upload files capabilities (Authors and above), check the applicable option under Settings > Discussion. This was the default behavior in 1.0.
144
  * Localization support; German included
145
 
146
+ = 1.0 - 2011-01-18 =
147
+ * Initial release.
148
+
149
  == Upgrade Notice ==
150
 
151
  = 2.1 =
155
  Upgraded to take advantage of *WordPress 3.5 and newer*. Does not support older versions! This has also *not* been tested with front end profile plug-ins - feedback welcome. Note that several language strings have been added or modified - revised translations would be welcome!
156
 
157
  = 1.3.1 =
158
+ Like WordPress 3.2, now *REQUIRES* PHP 5.2 or newer.
simple-local-avatars.dev.js DELETED
@@ -1,76 +0,0 @@
1
- var simple_local_avatar_frame, avatar_spinner, avatar_ratings, avatar_container, avatar_form_button;
2
- var avatar_working = false;
3
-
4
- jQuery(document).ready(function($){
5
- $( document.getElementById('simple-local-avatar-media') ).on( 'click', function(event) {
6
- event.preventDefault();
7
-
8
- if ( avatar_working )
9
- return;
10
-
11
- if ( simple_local_avatar_frame ) {
12
- simple_local_avatar_frame.open();
13
- return;
14
- }
15
-
16
- simple_local_avatar_frame = wp.media.frames.simple_local_avatar_frame = wp.media({
17
- title: i10n_SimpleLocalAvatars.insertMediaTitle,
18
- button: { text: i10n_SimpleLocalAvatars.insertIntoPost },
19
- library : { type : 'image'},
20
- multiple: false
21
- });
22
-
23
- simple_local_avatar_frame.on( 'select', function() {
24
- // We set multiple to false so only get one image from the uploader
25
- avatar_lock('lock');
26
- var avatar_url = simple_local_avatar_frame.state().get('selection').first().toJSON().id;
27
- jQuery.post( ajaxurl, { action: 'assign_simple_local_avatar_media', media_id: avatar_url, user_id: i10n_SimpleLocalAvatars.user_id, _wpnonce: i10n_SimpleLocalAvatars.mediaNonce }, function(data) {
28
- if ( data != '' ) {
29
- avatar_container.innerHTML = data;
30
- $( document.getElementById('simple-local-avatar-remove') ).show();
31
- avatar_ratings.disabled = false;
32
- avatar_lock('unlock');
33
- }
34
- });
35
- });
36
-
37
- simple_local_avatar_frame.open();
38
- });
39
-
40
- $( document.getElementById('simple-local-avatar-remove') ).on('click',function(event){
41
- event.preventDefault();
42
-
43
- if ( avatar_working )
44
- return;
45
-
46
- avatar_lock('lock');
47
- $.get( ajaxurl, { action: 'remove_simple_local_avatar', user_id: i10n_SimpleLocalAvatars.user_id, _wpnonce: i10n_SimpleLocalAvatars.deleteNonce })
48
- .done(function(data) {
49
- if ( data != '' ) {
50
- avatar_container.innerHTML = data;
51
- $( document.getElementById('simple-local-avatar-remove') ).hide();
52
- avatar_ratings.disabled = true;
53
- avatar_lock('unlock');
54
- }
55
- });
56
- });
57
- });
58
-
59
- function avatar_lock( lock_or_unlock ) {
60
- if ( undefined == avatar_spinner ) {
61
- avatar_ratings = document.getElementById('simple-local-avatar-ratings');
62
- avatar_spinner = jQuery( document.getElementById('simple-local-avatar-spinner') );
63
- avatar_container = document.getElementById('simple-local-avatar-photo');
64
- avatar_form_button = jQuery(avatar_ratings).closest('form').find('input[type=submit]');
65
- }
66
-
67
- if ( lock_or_unlock == 'unlock' ) {
68
- avatar_working = false;
69
- avatar_form_button.removeAttr('disabled');
70
- avatar_spinner.hide();
71
- } else {
72
- avatar_working = true;
73
- avatar_form_button.attr('disabled','disabled');
74
- avatar_spinner.show();
75
- }
76
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
simple-local-avatars.js DELETED
@@ -1 +0,0 @@
1
- function avatar_lock(e){if(undefined==avatar_spinner){avatar_ratings=document.getElementById("simple-local-avatar-ratings");avatar_spinner=jQuery(document.getElementById("simple-local-avatar-spinner"));avatar_container=document.getElementById("simple-local-avatar-photo");avatar_form_button=jQuery(avatar_ratings).closest("form").find("input[type=submit]")}if(e=="unlock"){avatar_working=false;avatar_form_button.removeAttr("disabled");avatar_spinner.hide()}else{avatar_working=true;avatar_form_button.attr("disabled","disabled");avatar_spinner.show()}}var simple_local_avatar_frame,avatar_spinner,avatar_ratings,avatar_container,avatar_form_button;var avatar_working=false;jQuery(document).ready(function(e){e(document.getElementById("simple-local-avatar-media")).on("click",function(t){t.preventDefault();if(avatar_working)return;if(simple_local_avatar_frame){simple_local_avatar_frame.open();return}simple_local_avatar_frame=wp.media.frames.simple_local_avatar_frame=wp.media({title:i10n_SimpleLocalAvatars.insertMediaTitle,button:{text:i10n_SimpleLocalAvatars.insertIntoPost},library:{type:"image"},multiple:false});simple_local_avatar_frame.on("select",function(){avatar_lock("lock");var t=simple_local_avatar_frame.state().get("selection").first().toJSON().id;jQuery.post(ajaxurl,{action:"assign_simple_local_avatar_media",media_id:t,user_id:i10n_SimpleLocalAvatars.user_id,_wpnonce:i10n_SimpleLocalAvatars.mediaNonce},function(t){if(t!=""){avatar_container.innerHTML=t;e(document.getElementById("simple-local-avatar-remove")).show();avatar_ratings.disabled=false;avatar_lock("unlock")}})});simple_local_avatar_frame.open()});e(document.getElementById("simple-local-avatar-remove")).on("click",function(t){t.preventDefault();if(avatar_working)return;avatar_lock("lock");e.get(ajaxurl,{action:"remove_simple_local_avatar",user_id:i10n_SimpleLocalAvatars.user_id,_wpnonce:i10n_SimpleLocalAvatars.deleteNonce}).done(function(t){if(t!=""){avatar_container.innerHTML=t;e(document.getElementById("simple-local-avatar-remove")).hide();avatar_ratings.disabled=true;avatar_lock("unlock")}})})})
 
simple-local-avatars.php CHANGED
@@ -3,18 +3,30 @@
3
  * Plugin Name: Simple Local Avatars
4
  * Plugin URI: https://10up.com/plugins/simple-local-avatars-wordpress/
5
  * Description: Adds an avatar upload field to user profiles. Generates requested sizes on demand, just like Gravatar! Simple and lightweight.
6
- * Version: 2.2.0
7
  * Requires at least: 4.6
8
- * Requires PHP: 5.3
9
  * Author: Jake Goldman, 10up
10
  * Author URI: https://10up.com
11
  * License: GPLv2 or later
12
  * License URI: https://www.gnu.org/licenses/gpl-2.0.html
13
  * Text Domain: simple-local-avatars
 
 
14
  */
15
 
 
 
16
  require_once dirname( __FILE__ ) . '/includes/class-simple-local-avatars.php';
17
 
 
 
 
 
 
 
 
 
18
  /**
19
  * Init the plugin.
20
  */
@@ -57,4 +69,5 @@ function simple_local_avatars_uninstall() {
57
  endforeach;
58
 
59
  delete_option( 'simple_local_avatars' );
 
60
  }
3
  * Plugin Name: Simple Local Avatars
4
  * Plugin URI: https://10up.com/plugins/simple-local-avatars-wordpress/
5
  * Description: Adds an avatar upload field to user profiles. Generates requested sizes on demand, just like Gravatar! Simple and lightweight.
6
+ * Version: 2.3.0
7
  * Requires at least: 4.6
8
+ * Requires PHP: 5.6
9
  * Author: Jake Goldman, 10up
10
  * Author URI: https://10up.com
11
  * License: GPLv2 or later
12
  * License URI: https://www.gnu.org/licenses/gpl-2.0.html
13
  * Text Domain: simple-local-avatars
14
+ *
15
+ * @package SimpleLocalAvatars
16
  */
17
 
18
+ define( 'SLA_PLUGIN_BASENAME', plugin_basename( __FILE__ ) );
19
+
20
  require_once dirname( __FILE__ ) . '/includes/class-simple-local-avatars.php';
21
 
22
+ // Global constants.
23
+ define( 'SLA_VERSION', '2.2.0' );
24
+ define( 'SLA_PLUGIN_URL', plugin_dir_url( __FILE__ ) );
25
+
26
+ if ( ! defined( 'SLA_IS_NETWORK' ) ) {
27
+ define( 'SLA_IS_NETWORK', Simple_Local_Avatars::is_network( plugin_basename( __FILE__ ) ) );
28
+ }
29
+
30
  /**
31
  * Init the plugin.
32
  */
69
  endforeach;
70
 
71
  delete_option( 'simple_local_avatars' );
72
+ delete_option( 'simple_local_avatars_migrations' );
73
  }