PluginProbe
Adminify – White Label, Admin Menu Editor, Login Customizer / 4.3.2
Adminify – White Label, Admin Menu Editor, Login Customizer v4.3.2
4.3.2 4.3.1 4.3.0 4.2.26 4.2.25 4.2.24 4.2.23 4.2.22 4.2.21 4.2.20 4.2.19 4.2.18 4.2.17 4.2.16 4.2.15 4.2.14 4.2.13 4.2.12 4.2.11 4.2.10 4.2.9 4.2.8 4.2.7 4.2.6 4.2.5 All 165 releases
← All changes | Inc/Classes/Tweaks.php +133 -17 4.2.254.3.2 View file →
@@ -64,8 +64,10 @@
64 64 // Add Custom Default Gravatar Image
65 65 if (!empty($this->custom_gravatar) && array_key_exists('enable', $this->custom_gravatar)) {
66 66 // Add Custom Default Gravatar Image
67 67 add_filter('avatar_defaults', [$this, 'add_custom_gravatar_image'], 99);
68 + // ...and serve it from this site rather than through gravatar.com.
69 + add_filter('get_avatar_data', [$this, 'serve_custom_gravatar_locally'], 99);
68 70 }
69 71
70 72 // If Admin bar Editor Plugin not Installed
71 73 if (! class_exists('\JewelTheme\AdminBarEditor\AdminBarEditor')) {
@@ -539,26 +541,147 @@
539 541 */
540 542 $wp_admin_bar->remove_node('wp-logo');
541 543 }
542 544
545 + /**
546 + * The avatar images an administrator configured in the plugin settings.
547 + *
548 + * Keyed by URL, because that is the identifier WordPress stores in the
549 + * `avatar_default` option and hands back to `get_avatar()` later.
550 + *
551 + * @return array<string,string> Avatar URL => label.
552 + */
553 + private function custom_gravatar_images()
554 + {
555 + $images = [];
556 +
557 + if ( empty( $this->custom_gravatar['image'] ) || ! is_array( $this->custom_gravatar['image'] ) ) {
558 + return $images;
559 + }
560 +
561 + foreach ( $this->custom_gravatar['image'] as $value ) {
562 + if ( empty( $value['avatar_image']['url'] ) ) {
563 + continue;
564 + }
565 +
566 + $avatar_url = esc_url_raw( $value['avatar_image']['url'] );
567 + $images[ $avatar_url ] = ! empty( $value['avatar_name'] )
568 + ? sanitize_text_field( $value['avatar_name'] )
569 + : __( 'Custom Gravatar', 'adminify' );
570 + }
571 +
572 + return $images;
573 + }
574 +
543 575 // Custom Avatars
544 576 public function add_custom_gravatar_image($avatar_defaults)
545 577 {
546 578 // Register the avatar images configured by the administrator in the plugin settings.
547 - if ( ! empty( $this->custom_gravatar['image'] ) && is_array( $this->custom_gravatar['image'] ) ) {
548 - foreach ( $this->custom_gravatar['image'] as $value ) {
549 - if ( empty( $value['avatar_image']['url'] ) ) {
550 - continue;
551 - }
552 - $avatar_url = esc_url_raw( $value['avatar_image']['url'] );
553 - $avatar_name = ! empty( $value['avatar_name'] ) ? sanitize_text_field( $value['avatar_name'] ) : __( 'Custom Gravatar', 'adminify' );
554 - $avatar_defaults[ $avatar_url ] = $avatar_name;
555 - }
579 + return array_merge( (array) $avatar_defaults, $this->custom_gravatar_images() );
580 + }
581 +
582 + /**
583 + * Serve a custom default avatar from this site instead of through gravatar.com.
584 + *
585 + * Core hands the chosen default to Gravatar as the `d=` query arg, which means
586 + * gravatar.com has to fetch the image from THIS server before it can serve it
587 + * back. That only works when the URL is publicly resolvable: on a local install,
588 + * a staging site behind HTTP auth, or an intranet, Gravatar cannot reach it and
589 + * every avatar that falls back to the default comes out broken.
590 + *
591 + * Gravatar precedence is preserved: a user who genuinely has a Gravatar still
592 + * gets theirs, because the custom image is only substituted once
593 + * email_has_gravatar() has established there is nothing to fall back FROM. That
594 + * keeps "Default Avatar" meaning what WordPress says it means.
595 + *
596 + * @param array $args Avatar data, after processing.
597 + * @return array
598 + */
599 + public function serve_custom_gravatar_locally( $args )
600 + {
601 + if ( empty( $args['default'] ) || ! is_string( $args['default'] ) ) {
602 + return $args;
556 603 }
557 604
558 - return $avatar_defaults;
605 + $images = $this->custom_gravatar_images();
606 +
607 + if ( ! isset( $images[ $args['default'] ] ) ) {
608 + return $args;
609 + }
610 +
611 + // `force_default` means the caller asked for the default image specifically -
612 + // the radio list on Settings > Discussion renders every option that way - so
613 + // there is nothing to look up.
614 + if ( empty( $args['force_default'] ) && $this->email_has_gravatar( $args['url'] ) ) {
615 + return $args;
616 + }
617 +
618 + // `found_avatar` is deliberately untouched: it only decides whether
619 + // get_avatar() adds the `avatar-default` class, which is correct here.
620 + $args['url'] = $args['default'];
621 +
622 + return $args;
559 623 }
560 624
625 + /**
626 + * Whether the address behind a gravatar.com URL actually has an avatar there.
627 + *
628 + * `d=404` is Gravatar's documented way of asking the question: instead of serving
629 + * a fallback image it answers 404 when the address is unknown. The answer is
630 + * cached per hash, so a busy comment thread costs one request per new address
631 + * rather than one per avatar rendered.
632 + *
633 + * The hash is read back out of the URL core just built rather than recomputed,
634 + * which avoids re-implementing its resolution of user IDs, comments, posts,
635 + * WP_User objects and raw hashes - and means a URL another plugin has already
636 + * pointed somewhere else is left alone.
637 + *
638 + * @param string $avatar_url The avatar URL core built.
639 + * @return bool True when the address has a Gravatar, or when it is not safe to say.
640 + */
641 + private function email_has_gravatar( $avatar_url )
642 + {
643 + if ( empty( $avatar_url ) || ! is_string( $avatar_url ) ) {
644 + return true;
645 + }
646 +
647 + $path = wp_parse_url( $avatar_url, PHP_URL_PATH );
648 + $hash = $path ? basename( $path ) : '';
649 +
650 + // SHA-256 in current core (hash('sha256', ...) in get_avatar_data), MD5 in
651 + // older releases. Anything else is not a gravatar.com avatar URL - another
652 + // plugin has already pointed it elsewhere - and is none of our business.
653 + if ( ! preg_match( '/^[a-f0-9]{32}$|^[a-f0-9]{64}$/i', $hash ) ) {
654 + return true;
655 + }
656 +
657 + $cache_key = 'adminify_has_gravatar_' . $hash;
658 + $cached = get_transient( $cache_key );
659 +
660 + if ( false !== $cached ) {
661 + return '1' === $cached;
662 + }
663 +
664 + $response = wp_remote_head(
665 + 'https://secure.gravatar.com/avatar/' . $hash . '?d=404&s=1',
666 + array( 'timeout' => 3 )
667 + );
668 +
669 + if ( is_wp_error( $response ) ) {
670 + // Offline, blocked, or too slow. Show the custom image rather than a URL
671 + // gravatar.com may not be able to resolve either, and ask again soon -
672 + // a temporary outage should not pin a real Gravatar out of view for a week.
673 + set_transient( $cache_key, '0', 15 * MINUTE_IN_SECONDS );
674 + return false;
675 + }
676 +
677 + $has_gravatar = 200 === (int) wp_remote_retrieve_response_code( $response );
678 +
679 + set_transient( $cache_key, $has_gravatar ? '1' : '0', WEEK_IN_SECONDS );
680 +
681 + return $has_gravatar;
682 + }
683 +
561 684 // Check Last Login Column
562 685 public function last_login_column_info( $user_login )
563 686 {
564 687 $user = get_user_by( 'login', $user_login );
@@ -772,15 +895,8 @@
772 895 }
773 896 }
774 897 }
775 898
776 -
777 - /** Control Interval Heartbeat API **/
778 - public function control_heartbeat_api($settings)
779 - {
780 - $settings['interval'] = 60;
781 - return $settings;
782 - }
783 899
784 900 /** Remove Query Strings from Scripts/Styles **/
785 901 public function remove_script_versions($src)
786 902 {