Completed
Push — kraftbj-patch-1 ( 599bd6...9b0476 )
by
unknown
145:59 queued 137:31
created

gravatar-hovercards.php ➔ grofiles_attach_cards()   A

Complexity

Conditions 5
Paths 5

Size

Total Lines 25

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
nc 5
nop 0
dl 0
loc 25
rs 9.2088
c 0
b 0
f 0
1
<?php
2
/**
3
 * Module Name: Gravatar Hovercards
4
 * Module Description: Enable pop-up business cards over commenters’ Gravatars.
5
 * Sort Order: 11
6
 * Recommendation Order: 13
7
 * First Introduced: 1.1
8
 * Requires Connection: No
9
 * Auto Activate: Yes
10
 * Module Tags: Social, Appearance
11
 * Feature: Appearance
12
 * Additional Search Queries: gravatar, hovercards
13
 */
14
15
define( 'GROFILES__CACHE_BUSTER', gmdate( 'YM' ) . 'aa' ); // Break CDN cache, increment when gravatar.com/js/gprofiles.js changes
16
17
function grofiles_hovercards_init() {
18
	add_filter( 'get_avatar',          'grofiles_get_avatar', 10, 2 );
19
	add_action( 'wp_enqueue_scripts',  'grofiles_attach_cards' );
20
	add_action( 'wp_footer',           'grofiles_extra_data' );
21
	add_action( 'admin_init',          'grofiles_add_settings' );
22
23
	add_action( 'load-index.php',              'grofiles_admin_cards' );
24
	add_action( 'load-users.php',              'grofiles_admin_cards' );
25
	add_action( 'load-edit-comments.php',      'grofiles_admin_cards' );
26
	add_action( 'load-options-discussion.php', 'grofiles_admin_cards_forced' );
27
28
	Jetpack::enable_module_configurable( __FILE__ );
29
	Jetpack::module_configuration_load( __FILE__, 'gravatar_hovercards_configuration_load' );
30
}
31
32
function gravatar_hovercards_configuration_load() {
33
	wp_safe_redirect( admin_url( 'options-discussion.php#show_avatars' ) );
34
	exit;
35
}
36
37
add_action( 'jetpack_modules_loaded', 'grofiles_hovercards_init' );
38
39
/* Hovercard Settings */
40
41
/**
42
 * Adds Gravatar Hovercard setting
43
 *
44
 * @todo - always print HTML, hide via CSS/JS if !show_avatars
45
 */
46
function grofiles_add_settings() {
47
	if ( !get_option( 'show_avatars' ) )
48
		return;
49
50
 	add_settings_field( 'gravatar_disable_hovercards', __( 'Gravatar Hovercards', 'jetpack' ), 'grofiles_setting_callback', 'discussion', 'avatars' );
51
 	register_setting( 'discussion', 'gravatar_disable_hovercards', 'grofiles_hovercard_option_sanitize' );
52
}
53
54
/**
55
 * HTML for Gravatar Hovercard setting
56
 */
57
function grofiles_setting_callback() {
58
	global $current_user;
59
60
	$checked = 'disabled' == get_option( 'gravatar_disable_hovercards' ) ? '' : 'checked="checked" ';
61
62
 	echo "<label id='gravatar-hovercard-options'><input {$checked}name='gravatar_disable_hovercards' id='gravatar_disable_hovercards' type='checkbox' value='enabled' class='code' /> " . __( "View people's profiles when you mouse over their Gravatars", 'jetpack' ) . "</label>";
63
?>
64
<style type="text/css">
65
#grav-profile-example img {
66
	float: left;
67
}
68
#grav-profile-example span {
69
	padding: 0 1em;
70
}
71
</style>
72
<script type="text/javascript">
73
// <![CDATA[
74
jQuery( function($) {
75
	var tr = $( '#gravatar_disable_hovercards' ).change( function() {
76
		if ( $( this ).is( ':checked' ) ) {
77
			$( '#grav-profile-example' ).slideDown( 'fast' );
78
		} else {
79
			$( '#grav-profile-example' ).slideUp( 'fast' );
80
		}
81
	} ).parents( 'tr' );
82
	var ftr = tr.parents( 'table' ).find( 'tr:first' );
83
	if ( ftr.length && !ftr.find( '#gravatar_disable_hovercards' ).length ) {
84
		ftr.after( tr );
85
	}
86
} );
87
// ]]>
88
</script>
89
	<p id="grav-profile-example" class="hide-if-no-js"<?php if ( !$checked ) echo ' style="display:none"'; ?>><?php echo get_avatar( $current_user->ID, 64 ); ?> <span><?php _e( 'Put your mouse over your Gravatar to check out your profile.', 'jetpack' ); ?> <br class="clear" /></span></p>
90
<?php
91
}
92
93
/**
94
 * Sanitation filter for Gravatar Hovercard setting
95
 */
96
function grofiles_hovercard_option_sanitize( $val ) {
97
	if ( 'disabled' == $val ) {
98
		return $val;
99
	}
100
101
	return $val ? 'enabled' : 'disabled';
102
}
103
104
105
/* Hovercard Display */
106
107
/**
108
 * Stores the gravatars' users that need extra profile data attached.
109
 *
110
 * Getter/Setter
111
 *
112
 * @param int|string|null $author Setter: User ID or email address.  Getter: null.
113
 *
114
 * @return mixed Setter: void.  Getter: array of user IDs and email addresses.
115
 */
116
function grofiles_gravatars_to_append( $author = null ) {
117
	static $authors = array();
118
119
	// Get
120
	if ( is_null( $author ) ) {
121
		return array_keys( $authors );
122
	}
123
124
	// Set
125
126
	if ( is_numeric( $author ) ) {
127
		$author = (int) $author;
128
	}
129
130
	$authors[$author] = true;
131
}
132
133
/**
134
 * Stores the user ID or email address for each gravatar generated.
135
 *
136
 * Attached to the 'get_avatar' filter.
137
 *
138
 * @param string $avatar The <img/> element of the avatar.
139
 * @param mixed $author User ID, email address, user login, comment object, user object, post object
140
 *
141
 * @return The <img/> element of the avatar.
142
 */
143
function grofiles_get_avatar( $avatar, $author ) {
144
	if ( is_numeric( $author ) ) {
145
		grofiles_gravatars_to_append( $author );
146
	} else if ( is_string( $author ) ) {
147
		if ( false !== strpos( $author, '@' ) ) {
148
			grofiles_gravatars_to_append( $author );
149
		} else {
150
			if ( $user = get_user_by( 'slug', $author ) )
151
				grofiles_gravatars_to_append( $user->ID );
152
		}
153
	} else if ( isset( $author->comment_type ) ) {
154
		if ( '' != $author->comment_type && 'comment' != $author->comment_type )
155
			return $avatar;
156
		if ( $author->user_id )
157
			grofiles_gravatars_to_append( $author->user_id );
158
		else
159
			grofiles_gravatars_to_append( $author->comment_author_email );
160
	} else if ( isset( $author->user_login ) ) {
161
		grofiles_gravatars_to_append( $author->ID );
162
	} else if ( isset( $author->post_author ) ) {
163
		grofiles_gravatars_to_append( $author->post_author );
164
	}
165
166
	return $avatar;
167
}
168
169
/**
170
 * Loads Gravatar Hovercard script.
171
 *
172
 * @todo is_singular() only?
173
 */
174
function grofiles_attach_cards() {
175
	global $blog_id;
176
177
	// Is the display of Avatars disabled?
178
	if ( ! get_option( 'show_avatars' ) ) {
179
		return;
180
	}
181
182
	// Is the display of Gravatar Hovercards disabled?
183
	if ( 'disabled' == Jetpack_Options::get_option_and_ensure_autoload( 'gravatar_disable_hovercards', '0' ) ) {
184
		return;
185
	}
186
187
	wp_enqueue_script( 'grofiles-cards', 'https://secure.gravatar.com/js/gprofiles.js', array( 'jquery' ), GROFILES__CACHE_BUSTER, true );
188
	wp_enqueue_script( 'wpgroho', plugins_url( 'wpgroho.js', __FILE__ ), array( 'grofiles-cards' ), false, true );
189
	if ( is_user_logged_in() ) {
190
		$cu = wp_get_current_user();
191
		$my_hash = md5( $cu->user_email );
192
	} else if ( !empty( $_COOKIE['comment_author_email_' . COOKIEHASH] ) ) {
193
		$my_hash = md5( $_COOKIE['comment_author_email_' . COOKIEHASH] );
194
	} else {
195
		$my_hash = '';
196
	}
197
	wp_localize_script( 'wpgroho', 'WPGroHo', compact( 'my_hash' ) );
198
}
199
200
function grofiles_attach_cards_forced() {
201
	add_filter( 'pre_option_gravatar_disable_hovercards', 'grofiles_force_gravatar_enable_hovercards' );
202
	grofiles_attach_cards();
203
}
204
205
function grofiles_force_gravatar_enable_hovercards() {
206
	return 'enabled';
207
}
208
209
function grofiles_admin_cards_forced() {
210
	add_action( 'admin_footer', 'grofiles_attach_cards_forced' );
211
}
212
213
function grofiles_admin_cards() {
214
	add_action( 'admin_footer', 'grofiles_attach_cards' );
215
}
216
217
function grofiles_extra_data() {
218
?>
219
	<div style="display:none">
220
<?php
221
	foreach ( grofiles_gravatars_to_append() as $author )
0 ignored issues
show
Bug introduced by
The expression grofiles_gravatars_to_append() of type array<integer,integer|string>|null is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
222
		grofiles_hovercards_data_html( $author );
223
?>
224
	</div>
225
<?php
226
}
227
228
/**
229
 * Echoes the data from grofiles_hovercards_data() as HTML elements.
230
 *
231
 * @since 5.5.0 Add support for a passed WP_User object
232
 *
233
 * @param int|string|WP_User $author User ID, email address, or a WP_User object
234
 */
235
function grofiles_hovercards_data_html( $author ) {
236
	$data = grofiles_hovercards_data( $author );
237
	$hash = '';
238
	if ( is_numeric( $author ) ) {
239
		$user = get_userdata( $author );
240
		if ( $user ) {
241
			$hash = md5( $user->user_email );
242
		}
243
	} elseif ( is_email( $author ) ) {
244
		$hash = md5( $author );
245
	} elseif ( is_a( $author, 'WP_User' ) ) {
246
		$hash = md5( $author->user_email );
247
	}
248
249
	if ( ! $hash ) {
250
		return;
251
	}
252
?>
253
	<div class="grofile-hash-map-<?php echo $hash; ?>">
254
<?php	foreach ( $data as $key => $value ) : ?>
255
		<span class="<?php echo esc_attr( $key ); ?>"><?php echo esc_html( $value ); ?></span>
256
<?php	endforeach; ?>
257
	</div>
258
<?php
259
}
260
261
262
/* API */
263
264
/**
265
 * Returns the PHP callbacks for data sources.
266
 *
267
 * 'grofiles_hovercards_data_callbacks' filter
268
 *
269
 * @return array( data_key => data_callback, ... )
0 ignored issues
show
Documentation introduced by
The doc-type array( could not be parsed: Expected "|" or "end of type", but got "(" at position 5. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
270
 */
271
function grofiles_hovercards_data_callbacks() {
272
	/**
273
	 * Filter the Gravatar Hovercard PHP callbacks.
274
	 *
275
	 * @module gravatar-hovercards
276
	 *
277
	 * @since 1.1.0
278
	 *
279
	 * @param array $args Array of data callbacks.
280
	 */
281
	return apply_filters( 'grofiles_hovercards_data_callbacks', array() );
282
}
283
284
/**
285
 * Keyed JSON object containing all profile data provided by registered callbacks
286
 *
287
 * @param int|strung $author User ID or email address
288
 *
289
 * @return array( data_key => data, ... )
0 ignored issues
show
Documentation introduced by
The doc-type array( could not be parsed: Expected "|" or "end of type", but got "(" at position 5. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
290
 */
291
function grofiles_hovercards_data( $author ) {
292
	$r = array();
293
	foreach ( grofiles_hovercards_data_callbacks() as $key => $callback ) {
294
		if ( !is_callable( $callback ) )
295
			continue;
296
		$data = call_user_func( $callback, $author, $key );
297
		if ( !is_null( $data ) )
298
			$r[$key] = $data;
299
	}
300
301
	return $r;
302
}
303